diff options
| -rw-r--r-- | CHANGES | 32 | ||||
| -rw-r--r-- | FL/Fl_Tree.H | 155 | ||||
| -rw-r--r-- | FL/Fl_Tree_Item.H | 51 | ||||
| -rw-r--r-- | FL/Fl_Tree_Prefs.H | 2 | ||||
| -rw-r--r-- | src/Fl_Tree.cxx | 1245 | ||||
| -rw-r--r-- | src/Fl_Tree_Item.cxx | 462 | ||||
| -rw-r--r-- | test/tree.fl | 208 |
7 files changed, 1650 insertions, 505 deletions
@@ -29,6 +29,38 @@ CHANGES IN FLTK 1.3.3 RELEASED: MMM - Added Fl_Tree::get_selected_items(), returns the selected items as an array - Added Fl_Tree::item_draw_callback(), letting one define a custom draw function for Fl_Tree_Item's. + - Fl_Tree: various related changes: + o Added horizontal scrollbar + o Separated draw() and tree size calculation + o Added new public methods: + > resize() -- uses optimized dim calc, avoids tree recalc + > next_item() -- added parameters: direction, visibility + > extend_selection() -- added parameters, improved algorithm + > calc_dimensions() -- calc tix/y/w/h, tox/y/w/h and scrollbars + > calc_tree() -- calc tree_w/tree_h + > recalc_tree() -- schedules calc_tree() + > first_visible_item(), last_visible_item(), next_visible_item() + > first_selected_item(), last_selected_item(), next_selected_item() + o Added protected variables: + > _tix/y/w/h -- tree widget 'inner' dimension + > _tox/y/w/h -- tree widget 'outer' dimension + > _tree_w,_tree_h -- entire tree hierarchy width/height + o Deprecated: + > item_clicked() -- use callback_item() instead + > first_visible() -- use first_visible_item() instead + > last_visible() -- use last_visible_item() instead + + - Fl_Tree_Item: various related changes: + o Added Fl_Tree ptr: needed for auto-recalc when item modified directly + o Added new methods tree(), recalc_tree() + o Added new ctor that accepts Fl_Tree* + o draw() parameters changed to include tree size calculations + o Deprecated: + > ctor using Fl_Tree_Prefs parameter (Fl_Tree* version better, + and must be used for 1.3.3 ABI features to work correctly) + > next_displayed() -- use next_visible() instead + > prev_displayed() -- use prev_visible() instead + - test/tree: added tests for newly added features CHANGES IN FLTK 1.3.2 RELEASED: Dec 12 2012 diff --git a/FL/Fl_Tree.H b/FL/Fl_Tree.H index ed2a2d526..9446e08d1 100644 --- a/FL/Fl_Tree.H +++ b/FL/Fl_Tree.H @@ -80,36 +80,38 @@ /// tree.end(); /// \endcode /// -/// \b FEATURES -/// -/// Items can be added with add(), -/// removed with remove(), -/// completely cleared with clear(), -/// inserted with insert() and insert_above(), -/// selected/deselected with select() and deselect(), -/// open/closed with open() and closed(). -/// Children of an item can be swapped around with Fl_Tree_Item::swap_children(), -/// sorting can be controlled when items are add()ed via sortorder(). -/// You can walk the entire tree with first() and next(). +/// \par FEATURES +/// Items can be added with add(),<BR> +/// removed with remove(),<BR> +/// completely cleared with clear(),<BR> +/// inserted with insert() and insert_above(),<BR> +/// selected/deselected with select() and deselect(),<BR> +/// open/closed with open() and close(),<BR> +/// positioned on the screen with show_item_top(), show_item_middle() and +/// show_item_bottom(),<BR> +/// item children can be swapped around with Fl_Tree_Item::swap_children(),<BR> +/// sorting can be controlled when items are add()ed via sortorder().<BR> +/// You can walk the entire tree with first() and next().<BR> +/// You can walk visible items with first_visible_item() +/// and next_visible_item().<BR> /// You can walk selected items with first_selected_item() and -/// next_selected_item(). +/// next_selected_item().<BR> /// Items can be found by their pathname using find_item(const char*), -/// and an item's pathname can be found with item_pathname(). -/// The selected items' colors are controlled by selection_color() (inherited from Fl_Widget). +/// and an item's pathname can be found with item_pathname().<BR> +/// The selected items' colors are controlled by selection_color() +/// (inherited from Fl_Widget).<BR> /// A hook is provided to allow you to redefine how item's labels are drawn -/// via Fl_Tree::item_draw_callback(). -/// -/// \b SELECTION OF ITEMS +/// via Fl_Tree::item_draw_callback().<BR> /// +/// \par SELECTION OF ITEMS /// The tree can have different selection behaviors controlled by selectmode(). /// The background color used for selected items is the Fl_Tree::selection_color(). /// The foreground color for selected items is controlled internally with fl_contrast(). /// -/// \b CHILD WIDGETS -/// +/// \par CHILD WIDGETS /// FLTK widgets (including custom widgets) can be assigned to tree items via /// Fl_Tree_Item::widget(). -/// +/// \par /// When a widget() is defined, the default behavior is for the widget() /// to be shown in place of the item's label (if it has one). /// Only the widget()'s width will be used; the widget()'s x() and y() position @@ -120,41 +122,38 @@ /// adding the FL_TREE_ITEM_HEIGHT_FROM_WIDGET flag causes widget's height /// to define the widget()'s height. /// -/// \b ICONS -/// +/// \par ICONS /// The tree's open/close icons can be redefined with /// Fl_Tree::openicon(), Fl_Tree::closeicon(). User icons /// can either be changed globally with Fl_Tree::usericon(), /// or on a per-item basis with Fl_Tree_Item::usericon(). -/// +/// \par /// Various default preferences can be globally manipulated via Fl_Tree_Prefs, /// including colors, margins, icons, connection lines, etc. /// -/// \b FONTS AND COLORS -/// +/// \par FONTS AND COLORS /// When adding new items to the tree, the new items get the /// defaults for fonts and colors from: -/// +/// \par /// - Fl_Tree::item_labelfont() -- The default item label font (default: FL_HELVETICA) /// - Fl_Tree::item_labelsize() -- The default item label size (default: FL_NORMAL_SIZE) /// - Fl_Tree::item_labelfgcolor() -- The default item label foreground color (default: FL_FOREGROUND_COLOR) /// - Fl_Tree::item_labelbgcolor() -- The default item label background color (default: 0xffffffff, which tree uses as 'transparent') -/// +/// \par /// Each item (Fl_Tree_Item) inherits a copy of these font/color attributes when created, /// and each item has its own methods to let the app change these values on a per-item basis /// using methods of the same name: -/// +/// \par /// - Fl_Tree_Item::item_labelfont() -- The item's label font (default: FL_HELVETICA) /// - Fl_Tree_Item::item_labelsize() -- The item's label size (default: FL_NORMAL_SIZE) /// - Fl_Tree_Item::item_labelfgcolor() -- The item's label foreground color (default: FL_FOREGROUND_COLOR) /// - Fl_Tree_Item::item_labelbgcolor() -- The item's label background color (default: 0xffffffff, which tree uses as 'transparent') /// -/// \b CALLBACKS -/// +/// \par CALLBACKS /// The tree's callback() will be invoked when items change state or are open/closed. /// when() controls when mouse/keyboard events invoke the callback. -/// callback_item() and callback_reason() can be used to determine the cause of the callback. eg: -/// +/// callback_item() and callback_reason() can be used to determine the cause of the callback. e.g. +/// \par /// \code /// void MyTreeCallback(Fl_Widget *w, void *data) { /// Fl_Tree *tree = (Fl_Tree*)w; @@ -168,13 +167,18 @@ /// } /// \endcode /// -/// To get the item's full menu pathname, you can use Fl_Tree::item_pathname(), eg: -/// +/// \par SIMPLE EXAMPLES +/// To find all the selected items: +/// \code +/// for ( Fl_Tree_Item *i=first_selected_item(); i; i=next_selected_item(i) ) +/// printf("Item %s is selected\n", i->label()); +/// \endcode +/// To get an item's full menu pathname, use Fl_Tree::item_pathname(), e.g. /// \code /// char pathname[256] = "???"; /// tree->item_pathname(pathname, sizeof(pathname), item); // eg. "Parent/Child/Item" /// \endcode -/// +/// \par /// To walk all the items of the tree from top to bottom: /// \code /// // Walk all the items in the tree, and print their labels @@ -182,7 +186,7 @@ /// printf("Item: %s\n", item->label()); /// } /// \endcode -/// +/// \par /// To recursively walk all the children of a particular item, /// define a function that uses recursion: /// \code @@ -194,8 +198,8 @@ /// } /// } /// \endcode -/// -/// To change the default label font and color for creating new items: +/// \par +/// To change the default label font and color when creating new items: /// \code /// tree = new Fl_Tree(..); /// tree->item_labelfont(FL_COURIER); // Use Courier font for all new items @@ -206,8 +210,8 @@ /// tree->add("Bbb"); /// [..] /// \endcode -/// -/// To change the font and color of all items in the tree: +/// \par +/// To change the font and color of all existing items in the tree: /// \code /// // Change the font and color of all items currently in the tree /// for ( Fl_Tree_Item *item = tree->first(); item; item = tree->next(item) ) { @@ -216,12 +220,19 @@ /// } /// \endcode /// +/// \par DISPLAY DESCRIPTION /// The following image shows the tree's various visual elements /// and the methods that control them: -/// +/// \par /// \image html tree-elements.png -/// \image latex tree-elements.png "Fl_Tree dimensions" width=6cm -/// +/// \image latex tree-elements.png "Fl_Tree elements" width=6cm +/// \par +/// The following shows the protected 'tree inner' (tix..) +/// and 'tree outer' (tox..) dimension variables: +/// \image html tree-dimensions.png "Fl_Tree inner/outer dimensions" width=6cm +/// \image latex tree-dimensions.png "Fl_Tree inner/outer dimensions" width=6cm +/// +/// \par KEYBOARD BINDINGS /// The following table lists keyboard bindings for navigating the tree: /// /// <TABLE BORDER="1" SUMMARY="Fl_Tree keyboard bindings."> @@ -317,23 +328,36 @@ class FL_EXPORT Fl_Tree : public Fl_Group { Fl_Tree_Reason _callback_reason; // reason for the callback Fl_Tree_Prefs _prefs; // all the tree's settings int _scrollbar_size; // size of scrollbar trough - #if FLTK_ABI_VERSION >= 10301 // NEW: Fl_Tree_Item *_lastselect; #else /*FLTK_ABI_VERSION*/ // OLD: static data inside handle() method #endif /*FLTK_ABI_VERSION*/ - void fix_scrollbar_order(); protected: - Fl_Scrollbar *_vscroll; ///< Vertical scrollbar + Fl_Scrollbar *_vscroll; ///< Vertical scrollbar +#if FLTK_ABI_VERSION >= 10303 + Fl_Scrollbar *_hscroll; ///< Horizontal scrollbar + int _tox,_toy,_tow,_toh; ///< Tree widget outer xywh dimension: outside scrollbars, inside widget border + int _tix,_tiy,_tiw,_tih; ///< Tree widget inner xywh dimension: inside borders + scrollbars + + /// the calculated width of the entire tree hierarchy. See calc_tree() + int _tree_w; + /// the calculated height of the entire tree hierarchy. See calc_tree() + int _tree_h; +#endif void item_clicked(Fl_Tree_Item* val); void do_callback_for_item(Fl_Tree_Item* item, Fl_Tree_Reason reason); +#if FLTK_ABI_VERSION >= 10303 +// next_visible_item() and extend_selection() moved to 'public' in ABI 1.3.3 +// undocmented draw_tree() dropped -- draw() does all the work now +#else Fl_Tree_Item *next_visible_item(Fl_Tree_Item *start, int dir); void extend_selection(Fl_Tree_Item *from, Fl_Tree_Item *to); int draw_tree(); +#endif public: Fl_Tree(int X, int Y, int W, int H, const char *L=0); @@ -341,7 +365,8 @@ public: int handle(int e); void draw(); void show_self(); - + void resize(int,int,int,int); + /////////////////////// // root methods /////////////////////// @@ -352,7 +377,7 @@ public: // Item creation/removal methods //////////////////////////////// Fl_Tree_Item *add(const char *path); - Fl_Tree_Item* add(Fl_Tree_Item *item, const char *name); + Fl_Tree_Item* add(Fl_Tree_Item *parent_item, const char *name); Fl_Tree_Item *insert_above(Fl_Tree_Item *above, const char *name); Fl_Tree_Item* insert(Fl_Tree_Item *item, const char *name, int pos); int remove(Fl_Tree_Item *item); @@ -368,15 +393,25 @@ public: const Fl_Tree_Item *find_clicked() const; Fl_Tree_Item *item_clicked(); Fl_Tree_Item *first(); - Fl_Tree_Item *first_visible(); + Fl_Tree_Item *first_visible(); // deprecated in ABI 10303 + Fl_Tree_Item *first_visible_item(); Fl_Tree_Item *next(Fl_Tree_Item *item=0); Fl_Tree_Item *prev(Fl_Tree_Item *item=0); Fl_Tree_Item *last(); - Fl_Tree_Item *last_visible(); + Fl_Tree_Item *last_visible(); // deprecated in ABI 10303 + Fl_Tree_Item *last_visible_item(); +#if FLTK_ABI_VERSION >= 10303 + Fl_Tree_Item *next_visible_item(Fl_Tree_Item *start, int dir); +#endif Fl_Tree_Item *first_selected_item(); - Fl_Tree_Item *next_selected_item(Fl_Tree_Item *item=0); + Fl_Tree_Item *last_selected_item(); + Fl_Tree_Item *next_item(Fl_Tree_Item *item, int dir=FL_Down, bool visible=false); #if FLTK_ABI_VERSION >= 10303 + Fl_Tree_Item *next_selected_item(Fl_Tree_Item *item=0, int dir=FL_Down); int get_selected_items(Fl_Tree_Item_Array &items); +#else + Fl_Tree_Item *next_selected_item(Fl_Tree_Item *item=0); + Fl_Tree_Item *next_selected_item(Fl_Tree_Item *item, int dir); #endif ////////////////////////// @@ -403,6 +438,18 @@ public: int deselect_all(Fl_Tree_Item *item=0, int docallback=1); int select_only(Fl_Tree_Item *selitem, int docallback=1); int select_all(Fl_Tree_Item *item=0, int docallback=1); +#if FLTK_ABI_VERSION >= 10303 + void extend_selection(Fl_Tree_Item *from, Fl_Tree_Item *to); + int extend_selection(Fl_Tree_Item *from, Fl_Tree_Item *to, int dir, int val, bool visible); + int extend_selection(Fl_Tree_Item *from, Fl_Tree_Item *to, int val, bool visible); +#else + // Adding overload if not at least one overload breaks ABI, so avoid + // See: http://www.ros.org/reps/rep-0009.html +private: + int extend_selection__(Fl_Tree_Item *from, Fl_Tree_Item *to, int dir, int val, bool visible); + int extend_selection__(Fl_Tree_Item *from, Fl_Tree_Item *to, int val, bool visible); +public: +#endif void set_item_focus(Fl_Tree_Item *item); Fl_Tree_Item *get_item_focus() const; int is_selected(Fl_Tree_Item *item) const; @@ -473,7 +520,10 @@ public: Fl_Tree_Item_Draw_Callback* item_draw_callback() const; void* item_draw_user_data() const; void do_item_draw_callback(Fl_Tree_Item *o) const; + void calc_dimensions(); + void calc_tree(); #endif + void recalc_tree(); int displayed(Fl_Tree_Item *item); void show_item(Fl_Tree_Item *item, int yoff); void show_item(Fl_Tree_Item *item); @@ -483,11 +533,14 @@ public: void display(Fl_Tree_Item *item); int vposition() const; void vposition(int pos); + int hposition() const; + void hposition(int pos); int is_scrollbar(Fl_Widget *w); int scrollbar_size() const; void scrollbar_size(int size); int is_vscroll_visible() const; + int is_hscroll_visible() const; /////////////////////// // callback related diff --git a/FL/Fl_Tree_Item.H b/FL/Fl_Tree_Item.H index 81c73fd64..b51d90907 100644 --- a/FL/Fl_Tree_Item.H +++ b/FL/Fl_Tree_Item.H @@ -36,7 +36,8 @@ /// \brief This file contains the definitions for Fl_Tree_Item /// -/// \brief Tree item +/// \class Fl_Tree_Item +/// \brief Tree widget item. /// /// This class is a single tree item, and manages all of the item's attributes. /// Fl_Tree_Item is used by Fl_Tree, which is comprised of many instances of Fl_Tree_Item. @@ -51,13 +52,23 @@ /// When you make changes to items, you'll need to tell the tree to redraw() /// for the changes to show up. /// +class Fl_Tree; class FL_EXPORT Fl_Tree_Item { +#if FLTK_ABI_VERSION >= 10303 + Fl_Tree *_tree; // parent tree +#endif const char *_label; // label (memory managed) Fl_Font _labelfont; // label's font face Fl_Fontsize _labelsize; // label's font size Fl_Color _labelfgcolor; // label's fg color Fl_Color _labelbgcolor; // label's bg color (0xffffffff is 'transparent') +#if FLTK_ABI_VERSION >= 10303 + /// \enum Fl_Tree_Item_Flags + enum Fl_Tree_Item_Flags { +#else + /// \enum enum { +#endif OPEN = 1<<0, ///> item is open VISIBLE = 1<<1, ///> item is visible ACTIVE = 1<<2, ///> item is active @@ -86,12 +97,18 @@ class FL_EXPORT Fl_Tree_Item { Fl_Tree_Item *_next_sibling; // next sibling (same level) #endif /*FLTK_ABI_VERSION*/ protected: + void _Init(const Fl_Tree_Prefs &prefs, Fl_Tree *tree); void show_widgets(); void hide_widgets(); void draw_vertical_connector(int x, int y1, int y2, const Fl_Tree_Prefs &prefs); void draw_horizontal_connector(int x1, int x2, int y, const Fl_Tree_Prefs &prefs); + void recalc_tree(); + const Fl_Tree_Item* find_clicked_(const Fl_Tree_Prefs &prefs, int yonly=0) const; // internal public: - Fl_Tree_Item(const Fl_Tree_Prefs &prefs); // CTOR + Fl_Tree_Item(const Fl_Tree_Prefs &prefs); // CTOR -- backwards compatible +#if FLTK_ABI_VERSION >= 10303 + Fl_Tree_Item(Fl_Tree *tree); // CTOR -- ABI 1.3.3+ +#endif ~Fl_Tree_Item(); // DTOR Fl_Tree_Item(const Fl_Tree_Item *o); // COPY CTOR int x() const { return(_xywh[0]); } @@ -103,7 +120,12 @@ public: int label_w() const { return(_label_xywh[2]); } int label_h() const { return(_label_xywh[3]); } int calc_item_height(const Fl_Tree_Prefs &prefs) const; +#if FLTK_ABI_VERSION >= 10303 + void draw(int X, int &Y, int W, Fl_Tree_Item *itemfocus, + int &tree_item_xmax, int lastchild=1, int render=1); +#else void draw(int X, int &Y, int W, Fl_Widget *tree, Fl_Tree_Item *itemfocus, const Fl_Tree_Prefs &prefs, int lastchild=1); +#endif void show_self(const char *indent = "") const; void label(const char *val); const char *label() const; @@ -117,6 +139,7 @@ public: /// Set item's label font face. void labelfont(Fl_Font val) { _labelfont = val; + recalc_tree(); // may change tree geometry } /// Get item's label font face. Fl_Font labelfont() const { @@ -125,6 +148,7 @@ public: /// Set item's label font size. void labelsize(Fl_Fontsize val) { _labelsize = val; + recalc_tree(); // may change tree geometry } /// Get item's label font size. Fl_Fontsize labelsize() const { @@ -159,6 +183,7 @@ public: /// Assign an FLTK widget to this item. void widget(Fl_Widget *val) { _widget = val; + recalc_tree(); // may change tree geometry } /// Return FLTK widget assigned to this item. Fl_Widget *widget() const { @@ -202,8 +227,10 @@ public: Fl_Tree_Item *next_sibling(); Fl_Tree_Item *prev_sibling(); void update_prev_next(int index); - Fl_Tree_Item *next_displayed(Fl_Tree_Prefs &prefs); - Fl_Tree_Item *prev_displayed(Fl_Tree_Prefs &prefs); + Fl_Tree_Item *next_displayed(Fl_Tree_Prefs &prefs); // deprecated + Fl_Tree_Item *prev_displayed(Fl_Tree_Prefs &prefs); // deprecated + Fl_Tree_Item *next_visible(Fl_Tree_Prefs &prefs); + Fl_Tree_Item *prev_visible(Fl_Tree_Prefs &prefs); /// Return the parent for this item. Returns NULL if we are the root. Fl_Tree_Item *parent() { @@ -219,6 +246,12 @@ public: void parent(Fl_Tree_Item *val) { _parent = val; } +#if FLTK_ABI_VERSION >= 10303 + /// Return the tree for this item. + const Fl_Tree *tree() const { + return(_tree); + } +#endif ////////////////// // State ////////////////// @@ -234,7 +267,7 @@ public: } /// Toggle the item's open/closed state. void open_toggle() { - is_open()?close():open(); + is_open()?close():open(); // handles calling recalc_tree() } /// Change the item's selection state to the optionally specified 'val'. /// If 'val' is not specified, the item will be selected. @@ -335,6 +368,7 @@ public: /// Set the item's user icon to an Fl_Image. '0' will disable. void usericon(Fl_Image *val) { _usericon = val; + recalc_tree(); // may change tree geometry } /// Get the item's user icon as an Fl_Image. Returns '0' if disabled. Fl_Image *usericon() const { @@ -343,8 +377,8 @@ public: ////////////////// // Events ////////////////// - const Fl_Tree_Item *find_clicked(const Fl_Tree_Prefs &prefs) const; - Fl_Tree_Item *find_clicked(const Fl_Tree_Prefs &prefs); + const Fl_Tree_Item *find_clicked(const Fl_Tree_Prefs &prefs, int yonly=0) const; + Fl_Tree_Item *find_clicked(const Fl_Tree_Prefs &prefs, int yonly=0); int event_on_collapse_icon(const Fl_Tree_Prefs &prefs) const; int event_on_label(const Fl_Tree_Prefs &prefs) const; /// Is this item the root of the tree? @@ -357,6 +391,9 @@ protected: #if FLTK_ABI_VERSION >= 10301 /// Set a flag to an on or off value. val is 0 or 1. inline void set_flag(unsigned short flag,int val) { + if ( flag==OPEN || flag==VISIBLE ) { + recalc_tree(); // may change tree geometry + } if ( val ) _flags |= flag; else _flags &= ~flag; } /// See if flag set. Returns 0 or 1. diff --git a/FL/Fl_Tree_Prefs.H b/FL/Fl_Tree_Prefs.H index 5ced88f4b..1b1a7b139 100644 --- a/FL/Fl_Tree_Prefs.H +++ b/FL/Fl_Tree_Prefs.H @@ -11,7 +11,7 @@ // FL/Fl_Tree_Prefs.H ////////////////////// // -// Fl_Tree -- This file is part of the Fl_Tree widget for FLTK +// Fl_Tree_Prefs -- This file is part of the Fl_Tree widget for FLTK // Copyright (C) 2009-2010 by Greg Ercolano. // // This library is free software. Distribution and use rights are outlined in diff --git a/src/Fl_Tree.cxx b/src/Fl_Tree.cxx index 455aba716..0cd69904d 100644 --- a/src/Fl_Tree.cxx +++ b/src/Fl_Tree.cxx @@ -27,12 +27,12 @@ // http://www.fltk.org/str.php // -// INTERNAL: scroller callback +// INTERNAL: scroller callback (hor+vert scroll) static void scroll_cb(Fl_Widget*,void *data) { ((Fl_Tree*)data)->redraw(); } -// INTERNAL: Parse elements from path into an array of null terminated strings +// INTERNAL: Parse elements from 'path' into an array of null terminated strings // Handles escape characters. // Path="/aa/bb" // Return: arr[0]="aa", arr[1]="bb", arr[2]=0 @@ -72,7 +72,7 @@ static char **parse_path(const char *path) { return(arr); } -// INTERNAL: Free the array returned by parse_path() +// INTERNAL: Free an array 'arr' returned by parse_path() static void free_path(char **arr) { if ( arr ) { if ( arr[0] ) { free((void*)arr[0]); } @@ -80,7 +80,9 @@ static void free_path(char **arr) { } } -// INTERNAL: Recursively descend tree hierarchy, accumulating total child count +// INTERNAL: Recursively descend 'item's tree hierarchy +// accumulating total child 'count' +// static int find_total_children(Fl_Tree_Item *item, int count=0) { count++; for ( int t=0; t<item->children(); t++ ) { @@ -91,7 +93,11 @@ static int find_total_children(Fl_Tree_Item *item, int count=0) { /// Constructor. Fl_Tree::Fl_Tree(int X, int Y, int W, int H, const char *L) : Fl_Group(X,Y,W,H,L) { +#if FLTK_ABI_VERSION >= 10303 + _root = new Fl_Tree_Item(this); +#else _root = new Fl_Tree_Item(_prefs); +#endif _root->parent(0); // we are root of tree _root->label("ROOT"); _item_focus = 0; @@ -109,11 +115,25 @@ Fl_Tree::Fl_Tree(int X, int Y, int W, int H, const char *L) : Fl_Group(X,Y,W,H,L box(FL_DOWN_BOX); color(FL_BACKGROUND2_COLOR, FL_SELECTION_COLOR); when(FL_WHEN_CHANGED); - _vscroll = new Fl_Scrollbar(0,0,0,0); // will be resized by draw() + int scrollsize = _scrollbar_size ? _scrollbar_size : Fl::scrollbar_size(); + _vscroll = new Fl_Scrollbar(X+W-scrollsize,Y,scrollsize,H); _vscroll->hide(); _vscroll->type(FL_VERTICAL); _vscroll->step(1); _vscroll->callback(scroll_cb, (void*)this); +#if FLTK_ABI_VERSION >= 10303 + _hscroll = new Fl_Scrollbar(X,Y+H-scrollsize,W,scrollsize); + _hscroll->hide(); + _hscroll->type(FL_HORIZONTAL); + _hscroll->step(1); + _hscroll->callback(scroll_cb, (void*)this); + _tox = _tix = X + Fl::box_dx(box()); + _toy = _tiy = Y + Fl::box_dy(box()); + _tow = _tiw = W - Fl::box_dw(box()); + _toh = _tih = H - Fl::box_dh(box()); + _tree_w = -1; + _tree_h = -1; +#endif end(); } @@ -122,26 +142,131 @@ Fl_Tree::~Fl_Tree() { if ( _root ) { delete _root; _root = 0; } } -/// Extend a selection between 'from' and 'to'. -/// Used by SHIFT-click to extend a selection between two items inclusive. +/// Extend the selection between and including \p 'from' and \p 'to' +/// depending on direction \p 'dir', \p 'val', and \p 'visible'. /// -void Fl_Tree::extend_selection(Fl_Tree_Item *from, Fl_Tree_Item *to) { - char on = 0; +/// Efficient: does not walk entire tree; starts with \p 'from' and stops +/// at \p 'to' while moving in direction \p 'dir'. Dir must be specified +/// though; when not available (such as during SHIFT-click operations), +/// the other method extend_selection(Fl_Tree_Item*,Fl_Tree_Item*,int,bool) +/// should be used. Handles calling redraw() if anything changed. +/// +/// \param[in] from Starting item +/// \param[in] to Ending item +/// \param[in] dir Direction to extend selection (FL_Up or FL_Down) +/// \param[in] val 0=deselect, 1=select, 2=toggle +/// \param[in] visible true=affect only open(), visible items,<br> +/// false=affect open or closed items (default) +/// \returns The number of items whose selection states were changed, if any. +/// +#if FLTK_ABI_VERSION >= 10303 +int Fl_Tree::extend_selection(Fl_Tree_Item *from, Fl_Tree_Item *to, + int dir, int val, bool visible ) { +#else +// Adding overload if not at least one overload breaks ABI, so avoid +int Fl_Tree::extend_selection__(Fl_Tree_Item *from, Fl_Tree_Item *to, + int dir, int val, bool visible ) { +#endif + int changed = 0; + for (Fl_Tree_Item *item=from; item; item = next_item(item, dir, visible) ) { + switch (val) { + case 0: + if ( deselect(item, when()) ) ++changed; + break; + case 1: + if ( select(item, when()) ) ++changed; + break; + case 2: + select_toggle(item, when()); + ++changed; // toggle always involves a change + break; + } + if ( item==to ) break; + } + return(changed); +} + +/// Extend a selection between \p 'from' and \p 'to' depending on \p 'visible'. +/// +/// Similar to the more efficient +/// extend_selection(Fl_Tree_Item*,Fl_Tree_Item*,int,int,bool) method, +/// but direction (up or down) doesn't need to be known.<br> +/// We're less efficient because we search the tree for to/from, then operate +/// on items in between. The more efficient method avoids the "search", +/// but necessitates a direction to be specified to find \p 'to'.<br> +/// Used by SHIFT-click to extend a selection between two items inclusive.<br> +/// Handles calling redraw() if anything changed. +/// +/// \param[in] from Starting item +/// \param[in] to Ending item +/// \param[in] val Select or deselect items (0=deselect, 1=select, 2=toggle) +/// \param[in] visible true=affect only open(), visible items,<br> +/// false=affect open or closed items (default) +/// \returns The number of items whose selection states were changed, if any. +/// +#if FLTK_ABI_VERSION >= 10303 +int Fl_Tree::extend_selection(Fl_Tree_Item *from, Fl_Tree_Item *to, + int val, bool visible) { +#else +// Adding overload if not at least one overload breaks ABI, so avoid +int Fl_Tree::extend_selection__(Fl_Tree_Item *from, Fl_Tree_Item *to, + int val, bool visible) { +#endif + int changed = 0; if ( from == to ) { - from->select(); - return; + if ( visible && !from->is_visible() ) return(0); // do nothing + switch (val) { + case 0: + if ( deselect(from, when()) ) ++changed; + break; + case 1: + if ( select(from, when()) ) ++changed; + break; + case 2: + select_toggle(from, when()); + ++changed; // always changed + break; + } + return(changed); } - for ( Fl_Tree_Item *item = first(); item; item = next(item) ) { - if ( (item == from) || (item == to) ) { - item->select(); // inclusive - on ^= 1; - } else if ( on ) { - item->select(); + char on = 0; + for ( Fl_Tree_Item *item = first(); item; item = item->next_visible(_prefs) ) { + if ( visible && !item->is_visible() ) continue; + if ( on || (item == from) || (item == to) ) { + switch (val) { + case 0: + if ( deselect(item, when()) ) ++changed; + break; + case 1: + if ( select(item, when()) ) ++changed; + break; + case 2: + select_toggle(item, when()); + ++changed; // toggle always involves a change + break; + } + if ( (item == from) || (item == to) ) { + on ^= 1; + if ( !on ) break; // done + } } } + return(changed); } +#if FLTK_ABI_VERSION >= 10303 +// nothing +#else +/// Extend a selection between \p 'from' and \p 'to'. +void Fl_Tree::extend_selection(Fl_Tree_Item *from, Fl_Tree_Item *to) { + const int val = 1; + const bool visible = false; + extend_selection__(from, to, val, visible); +} +#endif + /// Standard FLTK event handler for this widget. +/// \todo add Fl_Widget_Tracker (see Fl_Browser_.cxx::handle()) int Fl_Tree::handle(int e) { if (e == FL_NO_EVENT) return(0); // XXX: optimize to prevent slow resizes on large trees! int ret = 0; @@ -157,6 +282,7 @@ int Fl_Tree::handle(int e) { // Developer note: Fl_Browser_::handle() used for reference here.. // #include <FL/names.h> // for event debugging // fprintf(stderr, "DEBUG: %s (%d)\n", fl_eventnames[e], e); + if (e == FL_ENTER || e == FL_LEAVE) return(1); switch (e) { case FL_FOCUS: { @@ -164,10 +290,10 @@ int Fl_Tree::handle(int e) { // If a nav key was used to give us focus, and we've got no saved // focus widget, determine which item gets focus depending on nav key. // - if ( ! _item_focus ) { // no focus established yet? - switch (Fl::event_key()) { // determine if focus was navigated.. - case FL_Tab: { // received focus via TAB? - int updown = is_shift ? FL_Up : FL_Down; // SHIFT-TAB similar to Up, TAB similar to Down + if ( ! _item_focus ) { // no focus established yet? + switch (Fl::event_key()) { // determine if focus was navigated.. + case FL_Tab: { // received focus via TAB? + int updown = is_shift ? FL_Up : FL_Down; // SHIFT-TAB similar to Up, TAB similar to Down set_item_focus(next_visible_item(0, updown)); break; } @@ -196,7 +322,7 @@ int Fl_Tree::handle(int e) { if ( (Fl::focus() == this) && // tree has focus? _prefs.selectmode() > FL_TREE_SELECT_NONE ) { // select mode that supports kb events? if ( !_item_focus ) { // no current focus item? - set_item_focus(first_visible()); // use first vis item + set_item_focus(first_visible_item()); // use first vis item if ( Fl::event_key() == FL_Up || // Up or down? Fl::event_key() == FL_Down ) // ..if so, already did 'motion' return(1); // ..so just return. @@ -239,14 +365,10 @@ int Fl_Tree::handle(int e) { case FL_Left: { // LEFT: close children (if any) if ( _item_focus ) { if ( ekey == FL_Right && _item_focus->is_close() ) { - // Open closed item - open(_item_focus); - redraw(); + open(_item_focus); // open closed item ret = 1; } else if ( ekey == FL_Left && _item_focus->is_open() ) { - // Close open item - close(_item_focus); - redraw(); + close(_item_focus); // close open item ret = 1; } return(1); @@ -283,7 +405,7 @@ int Fl_Tree::handle(int e) { case FL_TREE_SELECT_MULTI: // Do a 'select all' select_all(); - _lastselect = first_visible(); + _lastselect = first_visible_item(); take_focus(); return(1); } @@ -306,14 +428,14 @@ int Fl_Tree::handle(int e) { // fprintf(stderr, "Fl_Tree::handle(): Event was %s (%d)\n", fl_eventnames[e], e); // DEBUGGING if ( ! _root ) return(ret); + static int last_my = 0; switch ( e ) { case FL_PUSH: { // clicked on tree - if (Fl::visible_focus() && handle(FL_FOCUS)) { - Fl::focus(this); - } - // Not extending a selection? zero lastselect + last_my = Fl::event_y(); // save for dragging direction.. + if (Fl::visible_focus() && handle(FL_FOCUS)) Fl::focus(this); Fl_Tree_Item *item = _root->find_clicked(_prefs); if ( !item ) { // clicked, but not on an item? + _lastselect = 0; switch ( _prefs.selectmode() ) { case FL_TREE_SELECT_NONE: break; @@ -324,26 +446,30 @@ int Fl_Tree::handle(int e) { } break; } - set_item_focus(item); // becomes new focus widget - redraw(); - ret |= 1; // handled + set_item_focus(item); // becomes new focus widget, calls redraw() if needed + ret |= 1; // handled if ( Fl::event_button() == FL_LEFT_MOUSE ) { if ( item->event_on_collapse_icon(_prefs) ) { // collapse icon clicked? - open_toggle(item); + open_toggle(item); // toggle open (handles redraw) } else if ( item->event_on_label(_prefs) && // label clicked? - (!item->widget() || !Fl::event_inside(item->widget())) && // not inside widget - (!_vscroll->visible() || !Fl::event_inside(_vscroll)) ) { // not on scroller + (!item->widget() || !Fl::event_inside(item->widget())) ) { // not inside widget switch ( _prefs.selectmode() ) { case FL_TREE_SELECT_NONE: break; case FL_TREE_SELECT_SINGLE: - select_only(item, when()); + select_only(item, when()); // select only this item (handles redraw) _lastselect = item; break; case FL_TREE_SELECT_MULTI: { if ( is_shift ) { // SHIFT+PUSH? if ( _lastselect ) { - extend_selection(_lastselect, item); + int val = is_ctrl ? 2 : 1; + bool visible = true; +#if FLTK_ABI_VERSION >= 10303 + extend_selection(_lastselect, item, val, visible); +#else + extend_selection__(_lastselect, item, val, visible); +#endif } else { select(item); // add to selection } @@ -361,61 +487,281 @@ int Fl_Tree::handle(int e) { break; } case FL_DRAG: { - // do the scrolling first: + // Do scrolling first.. + + // Detect up/down dragging int my = Fl::event_y(); - if ( my < y() ) { // above top? - int p = vposition()-(y()-my); - if ( p < 0 ) p = 0; - vposition(p); - } else if ( my > (y()+h()) ) { // below bottom? - int p = vposition()+(my-y()-h()); - if ( p > (int)_vscroll->maximum() ) p = (int)_vscroll->maximum(); - vposition(p); + int dir = (my>last_my) ? FL_Down : FL_Up; + last_my = my; + + // Handle autoscrolling + if ( my < y() ) { // Above top? + dir = FL_Up; // ..going up + int p = vposition()-(y()-my); // ..position above us + if ( p < 0 ) p = 0; // ..don't go above 0 + vposition(p); // ..scroll to new position + } else if ( my > (y()+h()) ) { // Below bottom? + dir = FL_Down; // ..going down + int p = vposition()+(my-y()-h()); // ..position below us + if ( p > (int)_vscroll->maximum() ) // ..don't go below bottom + p = (int)_vscroll->maximum(); + vposition(p); // ..scroll to new position } + + // Now handle the event.. + // During drag, only interested in left-mouse operations. + // if ( Fl::event_button() != FL_LEFT_MOUSE ) break; - Fl_Tree_Item *item = _root->find_clicked(_prefs); - if ( ! item ) break; - set_item_focus(item); // becomes new focus widget - redraw(); - ret |= 1; - // Item's label clicked? - if ( item->event_on_label(_prefs) && - (!item->widget() || !Fl::event_inside(item->widget())) && - (!_vscroll->visible() || !Fl::event_inside(_vscroll)) ) { - // Handle selection behavior - switch ( _prefs.selectmode() ) { - case FL_TREE_SELECT_NONE: - break; // no selection changes - case FL_TREE_SELECT_SINGLE: - select_only(item, when()); - _lastselect = item; - break; - case FL_TREE_SELECT_MULTI: - if ( is_ctrl ) { // CTRL-DRAG: toggle? - if ( _lastselect != item ) { // not already toggled from last microdrag? - select_toggle(item, when()); // toggle selection - } - } else { - select(item); // select this - } - _lastselect = item; - break; + Fl_Tree_Item *item = _root->find_clicked(_prefs, 1); // item we're on, vertically + if ( !item ) break; // not near item? ignore drag event + ret |= 1; // acknowledge event + set_item_focus(item); // becomes new focus item + if (item==_lastselect) break; // same item as before? avoid reselect + + // Handle selection behavior + switch ( _prefs.selectmode() ) { + case FL_TREE_SELECT_NONE: + break; // no selection changes + case FL_TREE_SELECT_SINGLE: { + select_only(item, when()); // select only this item (handles redraw) + break; + } + case FL_TREE_SELECT_MULTI: { + Fl_Tree_Item *from = next_visible_item(_lastselect, dir); // avoid reselecting item + Fl_Tree_Item *to = item; + int val = is_ctrl ? 2 : 1; // toggle_select() or just select()? + bool visible = true; +#if FLTK_ABI_VERSION >= 10303 + extend_selection(from, to, dir, val, visible); +#else + extend_selection__(from, to, dir, val, visible); +#endif + break; } } + _lastselect = item; // save current item for later break; } + case FL_RELEASE: + ret |= 1; + break; } return(ret); } +#if FLTK_ABI_VERSION >= 10303 +// nothing +#else +// Redraw timeout callback +// (Only need this hack for old ABI 10302 and older) +// static void redraw_soon(void *data) { ((Fl_Tree*)data)->redraw(); Fl::remove_timeout(redraw_soon, data); } +#endif +#if FLTK_ABI_VERSION >= 10303 +/// Recalculate widget dimensions and scrollbar visibility, +/// normally managed automatically. +/// +/// Low overhead way to update the tree widget's outer/inner dimensions +/// and re-determine scrollbar visibility based on these changes without +/// recalculating the entire size of the tree data. +/// +/// Assumes that either the tree's size in _tree_w/_tree_h are correct +/// so that scrollbar visibility can be calculated easily, or are both +/// zero indicating scrollbar visibility can't be calculated yet. +/// +/// This method is called when the widget is resize()ed or if the +/// scrollbar's sizes are changed (affects tree widget's inner dimensions +/// tix/y/w/h), and also used by calc_tree(). +/// +void Fl_Tree::calc_dimensions() { + // Calc tree outer xywh + // Area of the tree widget /outside/ scrollbars + // + _tox = x() + Fl::box_dx(box()); + _toy = y() + Fl::box_dy(box()); + _tow = w() - Fl::box_dw(box()); + _toh = h() - Fl::box_dh(box()); + + // Scrollbar visiblity + positions + // Calc this ONLY if tree_h and tree_w have been calculated. + // Zero values for these indicate calc in progress, but not done yet. + // + if ( _tree_h >= 0 && _tree_w >= 0 ) { + int scrollsize = _scrollbar_size ? _scrollbar_size : Fl::scrollbar_size(); + int vshow = _tree_h > _toh ? 1 : 0; + int hshow = _tree_w > _tow ? 1 : 0; + // See if one scroller's appearance affects the other's visibility + if ( hshow && !vshow && (_tree_h > (_toh-scrollsize)) ) vshow = 1; + if ( vshow && !hshow && (_tree_w > (_tow-scrollsize)) ) hshow = 1; + // vertical scrollbar visibility + if ( vshow ) { + _vscroll->show(); + _vscroll->resize(_tox+_tow-scrollsize, _toy, + scrollsize, h()-Fl::box_dh(box()) - (hshow ? scrollsize : 0)); + } else { + _vscroll->hide(); + _vscroll->value(0); + } + // horizontal scrollbar visibility + if ( hshow ) { + _hscroll->show(); + _hscroll->resize(_tox, _toy+_toh-scrollsize, + _tow - (vshow ? scrollsize : 0), scrollsize); + } else { + _hscroll->hide(); + _hscroll->value(0); + } + + // Calculate inner dimensions + // The area the tree occupies inside the scrollbars and margins + // + _tix = _tox; + _tiy = _toy; + _tiw = _tow - (_vscroll->visible() ? _vscroll->w() : 0); + _tih = _toh - (_hscroll->visible() ? _hscroll->h() : 0); + + // Scrollbar tab sizes + _vscroll->slider_size(float(_tih) / float(_tree_h)); + _vscroll->range(0.0, _tree_h - _tih); + + _hscroll->slider_size(float(_tiw) / float(_tree_w)); + _hscroll->range(0.0, _tree_w - _tiw); + } else { + // Best we can do without knowing tree_h/tree_w + _tix = _tox; + _tiy = _toy; + _tiw = _tow; + _tih = _toh; + } +} + +/// Recalculuates the tree's sizes and scrollbar visibility, +/// normally managed automatically. +/// +/// On return: +/// +/// - _tree_w will be the overall pixel width of the entire viewable tree +/// - _tree_h will be the overall pixel height "" +/// - scrollbar visibility and pan sizes are updated +/// - internal _tix/_tiy/_tiw/_tih dimensions are updated +/// +/// _tree_w/_tree_h include the tree's margins (e.g. marginleft()), +/// whether items are open or closed, label contents and font sizes, etc. +/// +/// The tree hierarchy's size is managed separately from the widget's +/// size as an optimization; this way resize() on the widget doesn't +/// involve recalculating the tree's hierarchy needlessly, as widget +/// size has no bearing on the tree hierarchy. +/// +/// The tree hierarchy's size only changes when items are added/removed, +/// open/closed, label contents or font sizes changed, margins changed, etc. +/// +/// This calculation involves walking the *entire* tree from top to bottom, +/// a potentially a slow calculation if the tree has many items (potentially +/// hundreds of thousands), and should therefore be called sparingly. +/// +/// For this reason, recalc_tree() is used as a way to /schedule/ +/// calculation when changes affect the tree hierarchy's size. +/// +/// Apps may want to call this method directly if the app makes changes +/// to the tree's geometry, then immediately needs to work with the tree's +/// new dimensions before an actual redraw (and recalc) occurs. (This +/// use by an app should only rarely be needed) +/// +void Fl_Tree::calc_tree() { + // Set tree width and height to zero, and recalc just _tox/_toy/_tow/_toh for now. + _tree_w = _tree_h = -1; + calc_dimensions(); + if ( !_root ) return; + // Walk the tree to determine its width and height. + // We need this to compute scrollbars.. + // By the end, 'Y' will be the lowest point on the tree + // + int X = _tix + _prefs.marginleft() + _hscroll->value(); + int Y = _tiy + _prefs.margintop() - _vscroll->value(); + int W = _tiw; + // Adjust root's X/W if connectors off + if (_prefs.connectorstyle() == FL_TREE_CONNECTOR_NONE) { + X -= _prefs.openicon()->w(); + W += _prefs.openicon()->w(); + } + int xmax = 0, render = 0, ytop = Y; + fl_font(_prefs.labelfont(), _prefs.labelsize()); + _root->draw(X, Y, W, 0, xmax, 1, render); // descend into tree without drawing (render=0) + // Save computed tree width and height + _tree_w = _prefs.marginleft() + xmax - X; // include margin in tree's width + _tree_h = _prefs.margintop() + Y - ytop; // include margin in tree's height + // Calc tree dims again; now that tree_w/tree_h are known, scrollbars are calculated. + calc_dimensions(); +} +#endif + +void Fl_Tree::resize(int X,int Y,int W, int H) { + fix_scrollbar_order(); + Fl_Group::resize(X,Y,W,H); +#if FLTK_ABI_VERSION >= 10303 + calc_dimensions(); +#endif + init_sizes(); +} + +#if FLTK_ABI_VERSION >= 10303 /// Standard FLTK draw() method, handles drawing the tree widget. void Fl_Tree::draw() { + fix_scrollbar_order(); + // Has tree recalc been scheduled? If so, do it + if ( _tree_w == -1 ) calc_tree(); + else calc_dimensions(); + // Let group draw box+label but *NOT* children. + // We handle drawing children ourselves by calling each item's draw() + { + // Draw group's bg + label + if ( damage() & ~FL_DAMAGE_CHILD) { // redraw entire widget? + Fl_Group::draw_box(); + Fl_Group::draw_label(); + } + if ( ! _root ) return; + // These values are changed during drawing + // By end, 'Y' will be the lowest point on the tree + int X = _tix + _prefs.marginleft() - _hscroll->value(); + int Y = _tiy + _prefs.margintop() - _vscroll->value(); + int W = _tiw - X + _tix; + // Adjust root's X/W if connectors off + if (_prefs.connectorstyle() == FL_TREE_CONNECTOR_NONE) { + X -= _prefs.openicon()->w(); + W += _prefs.openicon()->w(); + } + // Draw entire tree, starting with root + fl_push_clip(_tix,_tiy,_tiw,_tih); + { + int xmax = 0; + fl_font(_prefs.labelfont(), _prefs.labelsize()); + _root->draw(X, Y, W, // descend into tree here to draw it + (Fl::focus()==this)?_item_focus:0, // show focus item ONLY if Fl_Tree has focus + xmax, 1, 1); + } + fl_pop_clip(); + } + // Draw scrollbars last + draw_child(*_vscroll); + draw_child(*_hscroll); + // That little tile between the scrollbars + if ( _vscroll->visible() && _hscroll->visible() ) { + fl_color(_vscroll->color()); + fl_rectf(_hscroll->x()+_hscroll->w(), + _vscroll->y()+_vscroll->h(), + _vscroll->w(), + _hscroll->h()); + } +} +#else +void Fl_Tree::draw() { int ytoofar = draw_tree(); + // See if we're scrolled below bottom of tree // This can happen if someone just closed a large item. // If so, change scroller as needed. @@ -437,6 +783,7 @@ void Fl_Tree::draw() { } } +// This method is undocumented, and has been removed in ABI 1.3.3 int Fl_Tree::draw_tree() { int ret = 0; fix_scrollbar_order(); @@ -465,7 +812,6 @@ int Fl_Tree::draw_tree() { W += _prefs.openicon()->w(); } int Ysave = Y; - fl_push_clip(cx,cy,cw,ch); { fl_font(_prefs.labelfont(), _prefs.labelsize()); @@ -509,16 +855,18 @@ int Fl_Tree::draw_tree() { draw_child(*_vscroll); // draw scroll last return(ret); } +#endif /// Print the tree as 'ascii art' to stdout. /// Used mainly for debugging. +/// \todo should be const /// void Fl_Tree::show_self() { if ( ! _root ) return; _root->show_self(); } -/// Set the label for the root item. +/// Set the label for the root item to \p 'new_label'. /// /// Makes an internally managed copy of 'new_label'. /// @@ -532,23 +880,26 @@ Fl_Tree_Item* Fl_Tree::root() { return(_root); } -/// Adds a new item, given a 'menu style' path, eg: "/Parent/Child/item". +/// Adds a new item, given a menu style \p 'path'. /// Any parent nodes that don't already exist are created automatically. /// Adds the item based on the value of sortorder(). /// /// To specify items or submenus that contain slashes ('/' or '\') /// use an escape character to protect them, e.g. -/// /// \code /// tree->add("/Holidays/Photos/12\\/25\\2010"); // Adds item "12/25/2010" /// tree->add("/Pathnames/c:\\\\Program Files\\\\MyApp"); // Adds item "c:\Program Files\MyApp" /// \endcode -/// -/// \returns the child item created, or 0 on error. +/// \param[in] path The path to the item, e.g. "Flintsone/Fred". +/// \returns The new item added, or 0 on error. /// Fl_Tree_Item* Fl_Tree::add(const char *path) { if ( ! _root ) { // Create root if none +#if FLTK_ABI_VERSION >= 10303 + _root = new Fl_Tree_Item(this); +#else _root = new Fl_Tree_Item(_prefs); +#endif _root->parent(0); _root->label("ROOT"); } @@ -558,37 +909,38 @@ Fl_Tree_Item* Fl_Tree::add(const char *path) { return(item); } -/// Add a new child to a specific item in the tree. +/// Add a new child item labeled \p 'name' to the specified \p 'parent_item'. /// -/// \param[in] item The existing item to add new child to. Must not be NULL. +/// \param[in] parent_item The parent item the new child item will be added to. +/// Must not be NULL. /// \param[in] name The label for the new item -/// \returns the item that was added. +/// \returns The new item added. /// -Fl_Tree_Item* Fl_Tree::add(Fl_Tree_Item *item, const char *name) { - return(item->add(_prefs, name)); +Fl_Tree_Item* Fl_Tree::add(Fl_Tree_Item *parent_item, const char *name) { + return(parent_item->add(_prefs, name)); } -/// Inserts a new item above the specified Fl_Tree_Item, with the label set to 'name'. +/// Inserts a new item \p 'name' above the specified Fl_Tree_Item \p 'above'. /// \param[in] above -- the item above which to insert the new item. Must not be NULL. /// \param[in] name -- the name of the new item -/// \returns the item that was added, or 0 if 'above' could not be found. +/// \returns The new item added, or 0 if 'above' could not be found. /// Fl_Tree_Item* Fl_Tree::insert_above(Fl_Tree_Item *above, const char *name) { return(above->insert_above(_prefs, name)); } -/// Insert a new item into a tree-item's children at a specified position. +/// Insert a new item \p 'name' into \p 'item's children at position \p 'pos'. /// /// \param[in] item The existing item to insert new child into. Must not be NULL. /// \param[in] name The label for the new item /// \param[in] pos The position of the new item in the child list -/// \returns the item that was added. +/// \returns The new item added. /// Fl_Tree_Item* Fl_Tree::insert(Fl_Tree_Item *item, const char *name, int pos) { return(item->insert(_prefs, name, pos)); } -/// Remove the specified \p item from the tree. +/// Remove the specified \p 'item' from the tree. /// \p item may not be NULL. /// If it has children, all those are removed too. /// If item being removed has focus, no item will have focus. @@ -615,7 +967,8 @@ void Fl_Tree::clear() { _root->clear_children(); delete _root; _root = 0; } -/// Clear all the children of a particular node in the tree specified by \p item. + +/// Clear all the children for \p 'item'. /// Item may not be NULL. /// void Fl_Tree::clear_children(Fl_Tree_Item *item) { @@ -625,7 +978,7 @@ void Fl_Tree::clear_children(Fl_Tree_Item *item) { } } -/// Find the item, given a menu style path, eg: "/Parent/Child/item". +/// Find the item, given a menu style path, e.g. "/Parent/Child/item". /// There is both a const and non-const version of this method. /// Const version allows pure const methods to use this method /// to do lookups without causing compiler errors. @@ -639,7 +992,7 @@ void Fl_Tree::clear_children(Fl_Tree_Item *item) { /// \endcode /// /// \param[in] path -- the tree item's pathname to be found (e.g. "Flintstones/Fred") -/// \returns the item, or NULL if not found. +/// \returns The item, or NULL if not found. /// /// \see item_pathname() /// @@ -669,13 +1022,15 @@ const Fl_Tree_Item *Fl_Tree::find_item(const char *path) const { *s-- = c; \ } -/// Find the pathname for the specified \p item. -/// If \p item is NULL, root() is used. -/// The tree's root will be included in the pathname of showroot() is on. +/// Return \p 'pathname' of size \p 'pathnamelen' for the specified \p 'item'. +/// +/// If \p 'item' is NULL, root() is used.<br> +/// The tree's root will be included in the pathname of showroot() is on.<br> /// Menu items or submenus that contain slashes ('/' or '\') in their names /// will be escaped with a backslash. This is symmetrical with the add() /// function which uses the same escape pattern to set names. -/// \param[in] pathname The string to use to return the pathname +/// +/// \param[out] pathname The string to use to return the pathname /// \param[in] pathnamelen The maximum length of the string (including NULL). Must not be zero. /// \param[in] item The item whose pathname is to be returned. /// \returns @@ -712,17 +1067,17 @@ int Fl_Tree::item_pathname(char *pathname, int pathnamelen, const Fl_Tree_Item * return(0); } -/// Find the item that was clicked. +/// Find the item that was last clicked on. /// You should use callback_item() instead, which is fast, /// and is meant to be used within a callback to determine the item clicked. /// /// This method walks the entire tree looking for the first item that is -/// under the mouse (ie. at Fl::event_x()/Fl:event_y(). +/// under the mouse, i.e. at Fl::event_x() / Fl::event_y(). /// /// Use this method /only/ if you've subclassed Fl_Tree, and are receiving /// events before Fl_Tree has been able to process and update callback_item(). /// -/// \returns the item clicked, or 0 if no item was under the current event. +/// \returns The item clicked, or 0 if no item was under the current event. /// const Fl_Tree_Item* Fl_Tree::find_clicked() const { if ( ! _root ) return(NULL); @@ -733,67 +1088,74 @@ const Fl_Tree_Item* Fl_Tree::find_clicked() const { /// Should only be used by subclasses needing to change this value. /// Normally Fl_Tree manages this value. /// -/// Deprecated: use callback_item() instead. +/// \deprecated in 1.3.3 ABI -- use callback_item() instead. /// -void Fl_Tree::item_clicked(Fl_Tree_Item* val) { - _callback_item = val; +void Fl_Tree::item_clicked(Fl_Tree_Item* item) { + _callback_item = item; } /// Return the item that was last clicked. /// /// Valid only from within the callback(). /// -/// Deprecated: use callback_item() instead. -/// -/// \returns the item clicked, or 0 if none. +/// \returns The item clicked, or 0 if none. /// 0 may also be used to indicate several items were clicked/changed. +/// \deprecated in 1.3.3 ABI -- use callback_item() instead. /// Fl_Tree_Item* Fl_Tree::item_clicked() { return(_callback_item); } -/// Returns next visible item above (dir==Fl_Up) or below (dir==Fl_Down) the specified \p item. -/// If \p item is 0, returns first() if \p dir is Fl_Up, or last() if \p dir is FL_Down. +/// Returns next open(), visible item above (\p dir==FL_Up) +/// or below (\p dir==FL_Down) the specified \p 'item', or 0 if no more items. /// +/// If \p 'item' is 0, returns first() if \p 'dir' is FL_Up, +/// or last() if \p dir is FL_Down. +/// +/// \code +/// // Walk down the tree (forwards) +/// for ( Fl_Tree_Item *i=tree->first_visible_item(); i; i=tree->next_visible_item(i, FL_Down) ) +/// printf("Item: %s\n", i->label()); +/// +/// // Walk up the tree (backwards) +/// for ( Fl_Tree_Item *i=tree->last_visible_item(); i; i=tree->next_visible_item(i, FL_Up) ) +/// printf("Item: %s\n", i->label()); +/// \endcode /// \param[in] item The item above/below which we'll find the next visible item -/// \param[in] dir The direction to search. Can be FL_Up or FL_Down. +/// \param[in] dir The direction to search. Can be FL_Up or FL_Down. /// \returns The item found, or 0 if there's no visible items above/below the specified \p item. /// Fl_Tree_Item *Fl_Tree::next_visible_item(Fl_Tree_Item *item, int dir) { - if ( ! item ) { // no start item? - item = ( dir == FL_Up ) ? last_visible() : // wrap to bottom - first_visible(); // wrap to top - if ( ! item ) return(0); - if ( item->visible_r() ) return(item); // return first/last visible item - } - switch ( dir ) { - case FL_Up: return(item->prev_displayed(_prefs)); - case FL_Down: return(item->next_displayed(_prefs)); - default: return(item->next_displayed(_prefs)); - } + return next_item(item, dir, true); } -/// Returns the first item in the tree. +/// Returns the first item in the tree, or 0 if none. /// -/// Use this to walk the tree in the forward direction, eg: +/// Use this to walk the tree in the forward direction, e.g. /// \code -/// for ( Fl_Tree_Item *item = tree->first(); item; item = tree->next(item) ) { +/// for ( Fl_Tree_Item *item = tree->first(); item; item = tree->next(item) ) /// printf("Item: %s\n", item->label()); -/// } /// \endcode /// -/// \returns first item in tree, or 0 if none (tree empty). -/// \see first(),next(),last(),prev() +/// \returns First item in tree, or 0 if none (tree empty). +/// \see first(), next(), last(), prev() /// Fl_Tree_Item* Fl_Tree::first() { - return(_root); // first item always root + return(_root); // first item always root } -/// Returns the first visible item in the tree. -/// \returns first visible item in tree, or 0 if none. -/// \see first_visible(), last_visible() +/// Returns the first open(), visible item in the tree, or 0 if none. +/// \deprecated in 1.3.3 ABI -- use first_visible_item() instead. /// Fl_Tree_Item* Fl_Tree::first_visible() { + return(first_visible_item()); +} + +/// Returns the first open(), visible item in the tree, or 0 if none. +/// \returns First visible item in tree, or 0 if none. +/// \see first_visible_item(), last_visible_item(), next_visible_item() +/// +Fl_Tree_Item* Fl_Tree::first_visible_item() { Fl_Tree_Item *i = showroot() ? first() : next(first()); while ( i ) { if ( i->visible() ) return(i); @@ -802,39 +1164,36 @@ Fl_Tree_Item* Fl_Tree::first_visible() { return(0); } -/// Return the next item after \p item, or 0 if no more items. +/// Return the next item after \p 'item', or 0 if no more items. /// /// Use this code to walk the entire tree: /// \code -/// for ( Fl_Tree_Item *item = tree->first(); item; item = tree->next(item) ) { -/// printf("Item: %s\n", item->label()); -/// } +/// for ( Fl_Tree_Item *i = tree->first(); i; i = tree->next(i) ) +/// printf("Item: %s\n", i->label()); /// \endcode /// /// \param[in] item The item to use to find the next item. If NULL, returns 0. /// \returns Next item in tree, or 0 if at last item. /// -/// \see first(),next(),last(),prev() +/// \see first(), next(), last(), prev() /// Fl_Tree_Item *Fl_Tree::next(Fl_Tree_Item *item) { if ( ! item ) return(0); return(item->next()); } -/// Return the previous item before \p item, or 0 if no more items. -/// -/// This can be used to walk the tree in reverse, eg: +/// Return the previous item before \p 'item', or 0 if no more items. /// +/// This can be used to walk the tree in reverse, e.g. /// \code -/// for ( Fl_Tree_Item *item = tree->first(); item; item = tree->prev(item) ) { +/// for ( Fl_Tree_Item *item = tree->first(); item; item = tree->prev(item) ) /// printf("Item: %s\n", item->label()); -/// } /// \endcode /// /// \param[in] item The item to use to find the previous item. If NULL, returns 0. /// \returns Previous item in tree, or 0 if at first item. /// -/// \see first(),next(),last(),prev() +/// \see first(), next(), last(), prev() /// Fl_Tree_Item *Fl_Tree::prev(Fl_Tree_Item *item) { if ( ! item ) return(0); @@ -843,17 +1202,15 @@ Fl_Tree_Item *Fl_Tree::prev(Fl_Tree_Item *item) { /// Returns the last item in the tree. /// -/// This can be used to walk the tree in reverse, eg: +/// This can be used to walk the tree in reverse, e.g. /// /// \code -/// for ( Fl_Tree_Item *item = tree->last(); item; item = tree->prev() ) { +/// for ( Fl_Tree_Item *item = tree->last(); item; item = tree->prev() ) /// printf("Item: %s\n", item->label()); -/// } /// \endcode /// -/// \returns last item in the tree, or 0 if none (tree empty). -/// -/// \see first(),next(),last(),prev() +/// \returns Last item in the tree, or 0 if none (tree empty). +/// \see first(), next(), last(), prev() /// Fl_Tree_Item* Fl_Tree::last() { if ( ! _root ) return(0); @@ -864,12 +1221,18 @@ Fl_Tree_Item* Fl_Tree::last() { return(item); } -/// Returns the last visible item in the tree. -/// \returns last visible item in the tree, or 0 if none. -/// -/// \see first_visible(), last_visible() +/// Returns the last open(), visible item in the tree. +/// \deprecated in 1.3.3 ABI -- use last_visible_item() instead. /// Fl_Tree_Item* Fl_Tree::last_visible() { + return(last_visible_item()); +} + +/// Returns the last open(), visible item in the tree. +/// \returns Last visible item in the tree, or 0 if none. +/// \see first_visible_item(), last_visible_item(), next_visible_item() +/// +Fl_Tree_Item* Fl_Tree::last_visible_item() { Fl_Tree_Item *item = last(); while ( item ) { if ( item->visible() ) { @@ -886,46 +1249,182 @@ Fl_Tree_Item* Fl_Tree::last_visible() { /// Returns the first selected item in the tree. /// -/// Use this to walk the tree looking for all the selected items, eg: +/// Use this to walk the tree from top to bottom +/// looking for all the selected items, e.g. /// /// \code -/// for ( Fl_Tree_Item *item = tree->first_selected_item(); item; item = tree->next_selected_item(item) ) { -/// printf("Item: %s\n", item->label()); -/// } +/// // Walk tree forward, from top to bottom +/// for ( Fl_Tree_Item *i=tree->first_selected_item(); i; i=tree->next_selected_item(i) ) +/// printf("Selected item: %s\n", i->label()); /// \endcode /// -/// \returns The next selected item, or 0 if there are no more selected items. +/// \returns The first selected item, or 0 if none. +/// \see first_selected_item(), last_selected_item(), next_selected_item() /// Fl_Tree_Item *Fl_Tree::first_selected_item() { return(next_selected_item(0)); } -/// Returns the next selected item after \p item. +#if FLTK_ABI_VERSION >= 10303 +// nothing +#else +/// Returns the next selected item after \p 'item'. /// If \p item is 0, search starts at the first item (root). /// -/// Use this to walk the tree looking for all the selected items, eg: +/// This is a convenience method; equivalent to next_selected_item(item, FL_Down); +/// +/// Use this to walk the tree forward (downward) looking for all the selected items, e.g. /// \code -/// for ( Fl_Tree_Item *item = tree->first_selected_item(); item; item = tree->next_selected_item(item) ) { -/// printf("Item: %s\n", item->label()); -/// } +/// for ( Fl_Tree_Item *i = tree->first_selected_item(); i; i = tree->next_selected_item(i) ) +/// printf("Selected item: %s\n", i->label()); /// \endcode /// /// \param[in] item The item to use to find the next selected item. If NULL, first() is used. /// \returns The next selected item, or 0 if there are no more selected items. +/// \see first_selected_item(), last_selected_item(), next_selected_item() /// Fl_Tree_Item *Fl_Tree::next_selected_item(Fl_Tree_Item *item) { - if ( ! item ) { - if ( ! (item = first()) ) return(0); - if ( item->is_selected() ) return(item); + return(next_selected_item(item, FL_Down)); +} +#endif + +/// Returns the last selected item in the tree. +/// +/// Use this to walk the tree in reverse from bottom to top +/// looking for all the selected items, e.g. +/// +/// \code +/// // Walk tree in reverse, from bottom to top +/// for ( Fl_Tree_Item *i=tree->last_selected_item(); i; i=tree->next_selected_item(i, FL_Up) ) +/// printf("Selected item: %s\n", i->label()); +/// \endcode +/// +/// \returns The last selected item, or 0 if none. +/// \see first_selected_item(), last_selected_item(), next_selected_item() +/// +Fl_Tree_Item *Fl_Tree::last_selected_item() { + return(next_selected_item(0, FL_Up)); +} + +/// Returns next item after \p 'item' in direction \p 'dir' +/// depending on \p 'visible'. +/// +/// Next item will be above (if dir==FL_Up) or below (if dir==FL_Down). +/// If \p 'visible' is true, only items whose parents are open() will be returned. +/// If \p 'visible' is false, even items whose parents are close()ed will be returned. +/// +/// If \p item is 0, the return value will be: +/// <pre> +/// last_visible_item() - If \p visible=true and \p dir=FL_Up<br> +/// first_visible_item() - If \p visible=true and \p dir=FL_Down<br> +/// last() - If \p visible=false and \p dir=FL_Up<br> +/// first() - If \p visible=false and \p dir=FL_Down +/// </pre> +/// +/// \par Example use: +/// \code +/// // Walk down the tree showing open(), visible items +/// for ( Fl_Tree_Item *i=tree->first_visible_item(); i; i=tree->next_item(i, FL_Down, true) ) +/// printf("Item: %s\n", i->label()); +/// +/// // Walk up the tree showing open(), visible items +/// for ( Fl_Tree_Item *i=tree->last_visible_item(); i; i=tree->next_item(i, FL_Up, true) ) +/// printf("Item: %s\n", i->label()); +/// +/// // Walk down the tree showing all items (open or closed) +/// for ( Fl_Tree_Item *i=tree->first(); i; i=tree->next_item(i, FL_Down, false) ) +/// printf("Item: %s\n", i->label()); +/// +/// // Walk up the tree showing all items (open or closed) +/// for ( Fl_Tree_Item *i=tree->last(); i; i=tree->next_item(i, FL_Up, false) ) +/// printf("Item: %s\n", i->label()); +/// \endcode +/// +/// \param[in] item The item to use to find the next item. If NULL, returns 0. +/// \param[in] dir Can be FL_Up or FL_Down (default=FL_Down or 'next') +/// \param[in] visible true=return only open(), visible items,<br> +/// false=return open or closed items (default) +/// \returns Next item in tree in the direction and visibility specified, +/// or 0 if no more items of specified visibility in that direction. +/// \see first(), last(), next(),<BR> +/// first_visible_item(), last_visible_item(), next_visible_item(),<BR> +/// first_selected_item(), last_selected_item(), next_selected_item() +/// +Fl_Tree_Item *Fl_Tree::next_item(Fl_Tree_Item *item, int dir, bool visible) { + if ( ! item ) { // no start item? + if ( visible ) { + item = ( dir == FL_Up ) ? last_visible_item() : // wrap to bottom + first_visible_item(); // wrap to top + } else { + item = ( dir == FL_Up ) ? last() : // wrap to bottom + first(); // wrap to top + } + if ( ! item ) return(0); + if ( item->visible_r() ) return(item); // return first/last visible item + } + switch (dir) { + case FL_Up: + if ( visible ) return(item->prev_visible(_prefs)); + else return(item->prev()); + case FL_Down: + if ( visible ) return(item->next_visible(_prefs)); + else return(item->next()); + } + return(0); // unknown dir +} + +/// Returns the next selected item above or below \p 'item', depending on \p 'dir'. +/// If \p 'item' is 0, search starts at either first() or last(), depending on \p 'dir': +/// first() if \p 'dir' is FL_Down (default), last() if \p 'dir' is FL_Up. +/// +/// Use this to walk the tree looking for all the selected items, e.g. +/// \code +/// // Walk down the tree (forwards) +/// for ( Fl_Tree_Item *i=tree->first_selected_item(); i; i=tree->next_selected_item(i, FL_Down) ) +/// printf("Item: %s\n", i->label()); +/// +/// // Walk up the tree (backwards) +/// for ( Fl_Tree_Item *i=tree->last_selected_item(); i; i=tree->next_selected_item(i, FL_Up) ) +/// printf("Item: %s\n", i->label()); +/// \endcode +/// +/// \param[in] item The item above or below which we'll find the next selected item. +/// If NULL, first() is used if FL_Down, last() if FL_Up. +/// (default=NULL) +/// \param[in] dir The direction to go. +/// FL_Up for moving up the tree, +/// FL_Down for down the tree (default) +/// \returns The next selected item, or 0 if there are no more selected items. +/// \see first_selected_item(), last_selected_item(), next_selected_item() +/// +Fl_Tree_Item *Fl_Tree::next_selected_item(Fl_Tree_Item *item, int dir) { + switch (dir) { + case FL_Down: + if ( ! item ) { + if ( ! (item = first()) ) return(0); + if ( item->is_selected() ) return(item); + } + while ( (item = item->next()) ) + if ( item->is_selected() ) + return(item); + return(0); + case FL_Up: + if ( ! item ) { + if ( ! (item = last()) ) return(0); + if ( item->is_selected() ) return(item); + } + while ( (item = item->prev()) ) + if ( item->is_selected() ) + return(item); + return(0); } - while ( (item = item->next()) ) - if ( item->is_selected() ) - return(item); return(0); } #if FLTK_ABI_VERSION >= 10303 /* reason for this: Fl_Tree_Item_Array::manage_item_destroy() */ -/// Returns the currently selected items as an array. Example: +/// Returns the currently selected items as an array of \p 'ret_items'. +/// +/// Example: /// \code /// // Get selected items as an array /// Fl_Tree_Item_Array items; @@ -936,7 +1435,8 @@ Fl_Tree_Item *Fl_Tree::next_selected_item(Fl_Tree_Item *item) { /// ..do stuff with each selected item.. /// } /// \endcode -/// \param[in] ret_items The returned array of selected items. +/// +/// \param[out] ret_items The returned array of selected items. /// \returns The number of items in the returned array. /// \see first_selected_item(), next_selected_item() /// @@ -949,10 +1449,12 @@ int Fl_Tree::get_selected_items(Fl_Tree_Item_Array &ret_items) { } #endif -/// Open the specified 'item'. -/// This causes the item's children (if any) to be shown. -/// Handles redrawing if anything was actually changed. -/// Invokes the callback depending on the value of optional parameter \p docallback. +/// Open the specified \p 'item'. +/// +/// This causes the item's children (if any) to be shown.<br> +/// Invokes the callback depending on the value of optional +/// parameter \p 'docallback'.<br> +/// Handles calling redraw() if anything changed. /// /// The callback can use callback_item() and callback_reason() respectively to determine /// the item changed and the reason the callback was called. @@ -960,7 +1462,7 @@ int Fl_Tree::get_selected_items(Fl_Tree_Item_Array &ret_items) { /// \param[in] item -- the item to be opened. Must not be NULL. /// \param[in] docallback -- A flag that determines if the callback() is invoked or not: /// - 0 - callback() is not invoked -/// - 1 - callback() is invoked if item changed, +/// - 1 - callback() is invoked if item changed, (default) /// callback_reason() will be FL_TREE_REASON_OPENED /// \returns /// - 1 -- item was opened @@ -970,7 +1472,7 @@ int Fl_Tree::get_selected_items(Fl_Tree_Item_Array &ret_items) { /// int Fl_Tree::open(Fl_Tree_Item *item, int docallback) { if ( item->is_open() ) return(0); - item->open(); + item->open(); // handles recalc_tree() redraw(); if ( docallback ) { do_callback_for_item(item, FL_TREE_REASON_OPENED); @@ -978,10 +1480,12 @@ int Fl_Tree::open(Fl_Tree_Item *item, int docallback) { return(1); } -/// Opens the item specified by \p path (eg: "Parent/child/item"). -/// This causes the item's children (if any) to be shown. -/// Handles redrawing if anything was actually changed. -/// Invokes the callback depending on the value of optional parameter \p docallback. +/// Opens the item specified by \p 'path'. +/// +/// This causes the item's children (if any) to be shown.<br> +/// Invokes the callback depending on the value of optional +/// parameter \p 'docallback'.<br> +/// Handles calling redraw() if anything changed. /// /// Items or submenus that themselves contain slashes ('/' or '\') /// should be escaped, e.g. open("Holidays/12\\/25\//2010"). @@ -992,24 +1496,25 @@ int Fl_Tree::open(Fl_Tree_Item *item, int docallback) { /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred") /// \param[in] docallback -- A flag that determines if the callback() is invoked or not: /// - 0 - callback() is not invoked -/// - 1 - callback() is invoked if item changed, +/// - 1 - callback() is invoked if item changed (default), /// callback_reason() will be FL_TREE_REASON_OPENED /// \returns /// - 1 -- OK: item opened /// - 0 -- OK: item was already open, no change /// - -1 -- ERROR: item was not found -/// /// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason() /// int Fl_Tree::open(const char *path, int docallback) { Fl_Tree_Item *item = find_item(path); if ( ! item ) return(-1); - return(open(item, docallback)); + return(open(item, docallback)); // handles recalc_tree() } -/// Toggle the open state of \p item. -/// Handles redrawing if anything was actually changed. -/// Invokes the callback depending on the value of optional parameter \p docallback. +/// Toggle the open state of \p 'item'. +/// +/// Invokes the callback depending on the value of optional +/// parameter \p 'docallback'.<br> +/// Handles calling redraw() if anything changed. /// /// The callback can use callback_item() and callback_reason() respectively to determine /// the item changed and the reason the callback was called. @@ -1017,22 +1522,24 @@ int Fl_Tree::open(const char *path, int docallback) { /// \param[in] item -- the item whose open state is to be toggled. Must not be NULL. /// \param[in] docallback -- A flag that determines if the callback() is invoked or not: /// - 0 - callback() is not invoked -/// - 1 - callback() is invoked, callback_reason() will be either +/// - 1 - callback() is invoked (default), callback_reason() will be either /// FL_TREE_REASON_OPENED or FL_TREE_REASON_CLOSED /// /// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason() /// void Fl_Tree::open_toggle(Fl_Tree_Item *item, int docallback) { if ( item->is_open() ) { - close(item, docallback); + close(item, docallback); // handles recalc_tree() } else { - open(item, docallback); + open(item, docallback); // handles recalc_tree() } } -/// Closes the specified \p item. -/// Handles redrawing if anything was actually changed. -/// Invokes the callback depending on the value of optional parameter \p docallback. +/// Closes the specified \p 'item'. +/// +/// Invokes the callback depending on the value of optional +/// parameter \p 'docallback'.<br> +/// Handles calling redraw() if anything changed. /// /// The callback can use callback_item() and callback_reason() respectively to determine /// the item changed and the reason the callback was called. @@ -1040,17 +1547,16 @@ void Fl_Tree::open_toggle(Fl_Tree_Item *item, int docallback) { /// \param[in] item -- the item to be closed. Must not be NULL. /// \param[in] docallback -- A flag that determines if the callback() is invoked or not: /// - 0 - callback() is not invoked -/// - 1 - callback() is invoked if item changed, +/// - 1 - callback() is invoked if item changed (default), /// callback_reason() will be FL_TREE_REASON_CLOSED /// \returns /// - 1 -- item was closed /// - 0 -- item was already closed, no change -/// /// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason() /// int Fl_Tree::close(Fl_Tree_Item *item, int docallback) { if ( item->is_close() ) return(0); - item->close(); + item->close(); // handles recalc_tree() redraw(); if ( docallback ) { do_callback_for_item(item, FL_TREE_REASON_CLOSED); @@ -1058,9 +1564,11 @@ int Fl_Tree::close(Fl_Tree_Item *item, int docallback) { return(1); } -/// Closes the item specified by \p path, eg: "Parent/child/item". -/// Handles redrawing if anything was actually changed. -/// Invokes the callback depending on the value of optional parameter \p docallback. +/// Closes the item specified by \p 'path'. +/// +/// Invokes the callback depending on the value of optional +/// parameter \p 'docallback'.<br> +/// Handles calling redraw() if anything changed. /// /// Items or submenus that themselves contain slashes ('/' or '\') /// should be escaped, e.g. close("Holidays/12\\/25\//2010"). @@ -1071,22 +1579,21 @@ int Fl_Tree::close(Fl_Tree_Item *item, int docallback) { /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred") /// \param[in] docallback -- A flag that determines if the callback() is invoked or not: /// - 0 - callback() is not invoked -/// - 1 - callback() is invoked if item changed, +/// - 1 - callback() is invoked if item changed (default), /// callback_reason() will be FL_TREE_REASON_CLOSED /// \returns /// - 1 -- OK: item closed /// - 0 -- OK: item was already closed, no change /// - -1 -- ERROR: item was not found -/// /// \see open(), close(), is_open(), is_close(), callback_item(), callback_reason() /// int Fl_Tree::close(const char *path, int docallback) { Fl_Tree_Item *item = find_item(path); if ( ! item ) return(-1); - return(close(item, docallback)); + return(close(item, docallback)); // handles recalc_tree() } -/// See if \p item is open. +/// See if \p 'item' is open. /// /// Items that are 'open' are themselves not necessarily visible; /// one of the item's parents might be closed. @@ -1100,7 +1607,7 @@ int Fl_Tree::is_open(Fl_Tree_Item *item) const { return(item->is_open()?1:0); } -/// See if item specified by \p path (eg: "Parent/child/item") is open. +/// See if item specified by \p 'path' is open. /// /// Items or submenus that themselves contain slashes ('/' or '\') /// should be escaped, e.g. is_open("Holidays/12\\/25\//2010"). @@ -1113,6 +1620,7 @@ int Fl_Tree::is_open(Fl_Tree_Item *item) const { /// - 1 - OK: item is open /// - 0 - OK: item is closed /// - -1 - ERROR: item was not found +/// \see Fl_Tree_Item::visible_r() /// int Fl_Tree::is_open(const char *path) const { const Fl_Tree_Item *item = find_item(path); @@ -1120,7 +1628,7 @@ int Fl_Tree::is_open(const char *path) const { return(item->is_open()?1:0); } -/// See if the specified \p item is closed. +/// See if the specified \p 'item' is closed. /// /// \param[in] item -- the item to be tested. Must not be NULL. /// \returns @@ -1131,7 +1639,7 @@ int Fl_Tree::is_close(Fl_Tree_Item *item) const { return(item->is_close()); } -/// See if item specified by \p path (eg: "Parent/child/item") is closed. +/// See if item specified by \p 'path' is closed. /// /// Items or submenus that themselves contain slashes ('/' or '\') /// should be escaped, e.g. is_close("Holidays/12\\/25\//2010"). @@ -1148,9 +1656,10 @@ int Fl_Tree::is_close(const char *path) const { return(item->is_close()?1:0); } -/// Select the specified \p item. Use 'deselect()' to de-select it. -/// Handles redrawing if anything was actually changed. -/// Invokes the callback depending on the value of optional parameter \p docallback. +/// Select the specified \p 'item'. Use 'deselect()' to de-select it. +/// +/// Invokes the callback depending on the value of optional parameter \p docallback.<br> +/// Handles calling redraw() if anything changed. /// /// The callback can use callback_item() and callback_reason() respectively to determine /// the item changed and the reason the callback was called. @@ -1186,9 +1695,11 @@ int Fl_Tree::select(Fl_Tree_Item *item, int docallback) { return(0); } -/// Select the item specified by \p path (eg: "Parent/child/item"). -/// Handles redrawing if anything was actually changed. -/// Invokes the callback depending on the value of optional parameter \p docallback. +/// Select the item specified by \p 'path'. +/// +/// Invokes the callback depending on the value of optional +/// parameter \p 'docallback'.<br> +/// Handles calling redraw() if anything changed. /// /// Items or submenus that themselves contain slashes ('/' or '\') /// should be escaped, e.g. select("Holidays/12\\/25\//2010"). @@ -1199,7 +1710,7 @@ int Fl_Tree::select(Fl_Tree_Item *item, int docallback) { /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred") /// \param[in] docallback -- A flag that determines if the callback() is invoked or not: /// - 0 - the callback() is not invoked -/// - 1 - the callback() is invoked if item changed state, +/// - 1 - the callback() is invoked if item changed state (default), /// callback_reason() will be FL_TREE_REASON_SELECTED /// \returns /// - 1 : OK: item's state was changed @@ -1212,9 +1723,11 @@ int Fl_Tree::select(const char *path, int docallback) { return(select(item, docallback)); } -/// Toggle the select state of the specified \p item. -/// Handles redrawing if anything was actually changed. -/// Invokes the callback depending on the value of optional parameter \p docallback. +/// Toggle the select state of the specified \p 'item'. +/// +/// Invokes the callback depending on the value of optional +/// parameter \p 'docallback'.<br> +/// Handles calling redraw() if anything changed. /// /// The callback can use callback_item() and callback_reason() respectively to determine /// the item changed and the reason the callback was called. @@ -1222,7 +1735,7 @@ int Fl_Tree::select(const char *path, int docallback) { /// \param[in] item -- the item to be selected. Must not be NULL. /// \param[in] docallback -- A flag that determines if the callback() is invoked or not: /// - 0 - the callback() is not invoked -/// - 1 - the callback() is invoked, callback_reason() will be +/// - 1 - the callback() is invoked (default), callback_reason() will be /// either FL_TREE_REASON_SELECTED or FL_TREE_REASON_DESELECTED /// void Fl_Tree::select_toggle(Fl_Tree_Item *item, int docallback) { @@ -1236,8 +1749,10 @@ void Fl_Tree::select_toggle(Fl_Tree_Item *item, int docallback) { } /// De-select the specified \p item. -/// Handles redrawing if anything was actually changed. -/// Invokes the callback depending on the value of optional parameter \p docallback. +/// +/// Invokes the callback depending on the value of optional +/// parameter \p 'docallback'.<br> +/// Handles calling redraw() if anything changed. /// /// The callback can use callback_item() and callback_reason() respectively to determine /// the item changed and the reason the callback was called. @@ -1245,7 +1760,7 @@ void Fl_Tree::select_toggle(Fl_Tree_Item *item, int docallback) { /// \param[in] item -- the item to be selected. Must not be NULL. /// \param[in] docallback -- A flag that determines if the callback() is invoked or not: /// - 0 - the callback() is not invoked -/// - 1 - the callback() is invoked if item changed state, +/// - 1 - the callback() is invoked if item changed state (default), /// callback_reason() will be FL_TREE_REASON_DESELECTED /// \returns /// - 0 - item was already deselected, no change was made @@ -1264,9 +1779,11 @@ int Fl_Tree::deselect(Fl_Tree_Item *item, int docallback) { return(0); } -/// Deselect an item specified by \p path (eg: "Parent/child/item"). -/// Handles redrawing if anything was actually changed. -/// Invokes the callback depending on the value of optional parameter \p docallback. +/// Deselect an item specified by \p 'path'. +/// +/// Invokes the callback depending on the value of optional +/// parameter \p 'docallback'.<br> +/// Handles calling redraw() if anything changed. /// /// Items or submenus that themselves contain slashes ('/' or '\') /// should be escaped, e.g. deselect("Holidays/12\\/25\//2010"). @@ -1277,7 +1794,7 @@ int Fl_Tree::deselect(Fl_Tree_Item *item, int docallback) { /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred") /// \param[in] docallback -- A flag that determines if the callback() is invoked or not: /// - 0 - the callback() is not invoked -/// - 1 - the callback() is invoked if item changed state, +/// - 1 - the callback() is invoked if item changed state (default), /// callback_reason() will be FL_TREE_REASON_DESELECTED /// \returns /// - 1 - OK: item's state was changed @@ -1290,10 +1807,12 @@ int Fl_Tree::deselect(const char *path, int docallback) { return(deselect(item, docallback)); } -/// Deselect \p item and all its children. -/// If item is NULL, first() is used. -/// Handles calling redraw() if anything was changed. -/// Invokes the callback depending on the value of optional parameter \p docallback. +/// Deselect \p 'item' and all its children. +/// +/// If item is NULL, first() is used.<br> +/// Invokes the callback depending on the value of optional +/// parameter \p 'docallback'.<br> +/// Handles calling redraw() if anything changed. /// /// The callback can use callback_item() and callback_reason() respectively to determine /// the item changed and the reason the callback was called. @@ -1302,10 +1821,9 @@ int Fl_Tree::deselect(const char *path, int docallback) { /// If NULL, first() is used. /// \param[in] docallback -- A flag that determines if the callback() is invoked or not: /// - 0 - the callback() is not invoked -/// - 1 - the callback() is invoked for each item that changed state, +/// - 1 - the callback() is invoked for each item that changed state (default), /// callback_reason() will be FL_TREE_REASON_DESELECTED -/// -/// \returns count of how many items were actually changed to the deselected state. +/// \returns Count of how many items were actually changed to the deselected state. /// int Fl_Tree::deselect_all(Fl_Tree_Item *item, int docallback) { item = item ? item : first(); // NULL? use first() @@ -1322,10 +1840,12 @@ int Fl_Tree::deselect_all(Fl_Tree_Item *item, int docallback) { return(count); } -/// Select only the specified \p item, deselecting all others that might be selected. -/// If item is 0, first() is used. -/// Handles calling redraw() if anything was changed. -/// Invokes the callback depending on the value of optional parameter \p docallback. +/// Select only the specified \p 'item', deselecting all others that might be selected. +/// +/// If item is 0, first() is used.<br> +/// Invokes the callback depending on the value of optional +/// parameter \p 'docallback'.<br> +/// Handles calling redraw() if anything changed. /// /// The callback can use callback_item() and callback_reason() respectively to determine /// the item changed and the reason the callback was called. @@ -1333,10 +1853,10 @@ int Fl_Tree::deselect_all(Fl_Tree_Item *item, int docallback) { /// \param[in] selitem The item to be selected. If NULL, first() is used. /// \param[in] docallback -- A flag that determines if the callback() is invoked or not: /// - 0 - the callback() is not invoked -/// - 1 - the callback() is invoked for each item that changed state, +/// - 1 - the callback() is invoked for each item that changed state (default), /// callback_reason() will be either FL_TREE_REASON_SELECTED or /// FL_TREE_REASON_DESELECTED -/// \returns the number of items whose selection states were changed, if any. +/// \returns The number of items whose selection states were changed, if any. /// int Fl_Tree::select_only(Fl_Tree_Item *selitem, int docallback) { selitem = selitem ? selitem : first(); // NULL? use first() @@ -1372,10 +1892,12 @@ int Fl_Tree::select_only(Fl_Tree_Item *selitem, int docallback) { return(changed); } -/// Select \p item and all its children. -/// If item is NULL, first() is used. -/// Handles calling redraw() if anything was changed. -/// Invokes the callback depending on the value of optional parameter \p docallback. +/// Select \p 'item' and all its children. +/// +/// If item is NULL, first() is used.<br> +/// Invokes the callback depending on the value of optional +/// parameter \p 'docallback'.<br> +/// Handles calling redraw() if anything changed. /// /// The callback can use callback_item() and callback_reason() respectively to determine /// the item changed and the reason the callback was called. @@ -1384,9 +1906,9 @@ int Fl_Tree::select_only(Fl_Tree_Item *selitem, int docallback) { /// If NULL, first() is used. /// \param[in] docallback -- A flag that determines if the callback() is invoked or not: /// - 0 - the callback() is not invoked -/// - 1 - the callback() is invoked for each item that changed state, +/// - 1 - the callback() is invoked for each item that changed state (default), /// callback_reason() will be FL_TREE_REASON_SELECTED -/// \returns count of how many items were actually changed to the selected state. +/// \returns Count of how many items were actually changed to the selected state. /// int Fl_Tree::select_all(Fl_Tree_Item *item, int docallback) { item = item ? item : first(); // NULL? use first() @@ -1409,6 +1931,7 @@ Fl_Tree_Item* Fl_Tree::get_item_focus() const { } /// Set the item that currently should have keyboard focus. +/// /// Handles calling redraw() to update the focus box (if it is visible). /// /// \param[in] item The item that should take focus. If NULL, none will have focus. @@ -1420,7 +1943,7 @@ void Fl_Tree::set_item_focus(Fl_Tree_Item *item) { } } -/// See if the specified \p item is selected. +/// See if the specified \p 'item' is selected. /// /// \param[in] item -- the item to be tested. Must not be NULL. /// @@ -1432,7 +1955,7 @@ int Fl_Tree::is_selected(Fl_Tree_Item *item) const { return(item->is_selected()?1:0); } -/// See if item specified by \p path (eg: "Parent/child/item") is selected. +/// See if item specified by \p 'path' is selected. /// /// Items or submenus that themselves contain slashes ('/' or '\') /// should be escaped, e.g. is_selected("Holidays/12\\/25\//2010"). @@ -1522,6 +2045,7 @@ int Fl_Tree::marginleft() const { void Fl_Tree::marginleft(int val) { _prefs.marginleft(val); redraw(); + recalc_tree(); } /// Get the amount of white space (in pixels) that should appear @@ -1537,6 +2061,7 @@ int Fl_Tree::margintop() const { void Fl_Tree::margintop(int val) { _prefs.margintop(val); redraw(); + recalc_tree(); } #if FLTK_ABI_VERSION >= 10301 @@ -1553,6 +2078,7 @@ int Fl_Tree::marginbottom() const { void Fl_Tree::marginbottom(int val) { _prefs.marginbottom(val); redraw(); + recalc_tree(); } #endif /*FLTK_ABI_VERSION*/ @@ -1569,6 +2095,7 @@ int Fl_Tree::linespacing() const { void Fl_Tree::linespacing(int val) { _prefs.linespacing(val); redraw(); + recalc_tree(); } /// Get the amount of white space (in pixels) that should appear @@ -1584,40 +2111,50 @@ int Fl_Tree::openchild_marginbottom() const { void Fl_Tree::openchild_marginbottom(int val) { _prefs.openchild_marginbottom(val); redraw(); + recalc_tree(); } + /// Get the amount of white space (in pixels) that should appear /// to the left of the usericon. int Fl_Tree::usericonmarginleft() const { return(_prefs.usericonmarginleft()); } + /// Set the amount of white space (in pixels) that should appear /// to the left of the usericon. void Fl_Tree::usericonmarginleft(int val) { _prefs.usericonmarginleft(val); redraw(); + recalc_tree(); } + /// Get the amount of white space (in pixels) that should appear /// to the left of the label text. int Fl_Tree::labelmarginleft() const { return(_prefs.labelmarginleft()); } + /// Set the amount of white space (in pixels) that should appear /// to the left of the label text. void Fl_Tree::labelmarginleft(int val) { _prefs.labelmarginleft(val); redraw(); + recalc_tree(); } + #if FLTK_ABI_VERSION >= 10301 /// Get the amount of white space (in pixels) that should appear /// to the left of the child fltk widget (if any). int Fl_Tree::widgetmarginleft() const { return(_prefs.widgetmarginleft()); } + /// Set the amount of white space (in pixels) that should appear /// to the left of the child fltk widget (if any). void Fl_Tree::widgetmarginleft(int val) { _prefs.widgetmarginleft(val); redraw(); + recalc_tree(); } #endif /*FLTK_ABI_VERSION*/ @@ -1634,6 +2171,7 @@ int Fl_Tree::connectorwidth() const { void Fl_Tree::connectorwidth(int val) { _prefs.connectorwidth(val); redraw(); + recalc_tree(); } /// Returns the Fl_Image being used as the default user icon for all @@ -1656,6 +2194,7 @@ Fl_Image* Fl_Tree::usericon() const { void Fl_Tree::usericon(Fl_Image *val) { _prefs.usericon(val); redraw(); + recalc_tree(); } /// Returns the icon to be used as the 'open' icon. @@ -1674,6 +2213,7 @@ Fl_Image* Fl_Tree::openicon() const { void Fl_Tree::openicon(Fl_Image *val) { _prefs.openicon(val); redraw(); + recalc_tree(); } /// Returns the icon to be used as the 'close' icon. @@ -1692,6 +2232,7 @@ Fl_Image* Fl_Tree::closeicon() const { void Fl_Tree::closeicon(Fl_Image *val) { _prefs.closeicon(val); redraw(); + recalc_tree(); } /// Returns 1 if the collapse icon is enabled, 0 if not. @@ -1710,6 +2251,7 @@ int Fl_Tree::showcollapse() const { void Fl_Tree::showcollapse(int val) { _prefs.showcollapse(val); redraw(); + recalc_tree(); } /// Returns 1 if the root item is to be shown, or 0 if not. @@ -1724,6 +2266,7 @@ int Fl_Tree::showroot() const { void Fl_Tree::showroot(int val) { _prefs.showroot(val); redraw(); + recalc_tree(); } /// Returns the line drawing style for inter-connecting items. @@ -1732,13 +2275,15 @@ Fl_Tree_Connector Fl_Tree::connectorstyle() const { } /// Sets the line drawing style for inter-connecting items. +/// See ::Fl_Tree_Connector for possible values. +/// void Fl_Tree::connectorstyle(Fl_Tree_Connector val) { _prefs.connectorstyle(val); redraw(); } /// Set the default sort order used when items are added to the tree. -/// See Fl_Tree_Sort for possible values. +/// See ::Fl_Tree_Sort for possible values. /// Fl_Tree_Sort Fl_Tree::sortorder() const { return(_prefs.sortorder()); @@ -1751,7 +2296,7 @@ void Fl_Tree::sortorder(Fl_Tree_Sort val) { } /// Sets the style of box used to draw selected items. -/// This is an fltk Fl_Boxtype. +/// This is an fltk ::Fl_Boxtype. /// The default is influenced by FLTK's current Fl::scheme() /// Fl_Boxtype Fl_Tree::selectbox() const { @@ -1759,7 +2304,7 @@ Fl_Boxtype Fl_Tree::selectbox() const { } /// Gets the style of box used to draw selected items. -/// This is an fltk Fl_Boxtype. +/// This is an fltk ::Fl_Boxtype. /// The default is influenced by FLTK's current Fl::scheme() /// void Fl_Tree::selectbox(Fl_Boxtype val) { @@ -1773,6 +2318,8 @@ Fl_Tree_Select Fl_Tree::selectmode() const { } /// Sets the tree's selection mode. +/// See ::Fl_Tree_Select for possible values. +/// void Fl_Tree::selectmode(Fl_Tree_Select val) { _prefs.selectmode(val); } @@ -1784,6 +2331,8 @@ Fl_Tree_Item_Reselect_Mode Fl_Tree::item_reselect_mode() const { } /// Sets the item re/selection mode +/// See ::Fl_Tree_Item_Reselect_Mode for possible values. +/// void Fl_Tree::item_reselect_mode(Fl_Tree_Item_Reselect_Mode mode) { _prefs.item_reselect_mode(mode); } @@ -1795,68 +2344,79 @@ Fl_Tree_Item_Draw_Mode Fl_Tree::item_draw_mode() const { return(_prefs.item_draw_mode()); } -/// Set the 'item draw mode' used for the tree to \p val. +/// Set the 'item draw mode' used for the tree to \p 'mode'. /// This affects how items in the tree are drawn, /// such as when a widget() is defined. -/// See Fl_Tree_Item_Draw_Mode for possible values. +/// See ::Fl_Tree_Item_Draw_Mode for possible values. /// -void Fl_Tree::item_draw_mode(Fl_Tree_Item_Draw_Mode val) { - _prefs.item_draw_mode(val); +void Fl_Tree::item_draw_mode(Fl_Tree_Item_Draw_Mode mode) { + _prefs.item_draw_mode(mode); } -void Fl_Tree::item_draw_mode(int val) { - _prefs.item_draw_mode(Fl_Tree_Item_Draw_Mode(val)); + +/// Set the 'item draw mode' used for the tree to integer \p 'mode'. +/// This affects how items in the tree are drawn, +/// such as when a widget() is defined. +/// See ::Fl_Tree_Item_Draw_Mode for possible values. +/// +void Fl_Tree::item_draw_mode(int mode) { + _prefs.item_draw_mode(Fl_Tree_Item_Draw_Mode(mode)); } /// Set a callback to be invoked to handle drawing the Fl_Tree_Item /// instead of the default label drawing behavior. Lets one define -/// custom drawing behavior for Fl_Tree_Item's. eg: +/// custom drawing behavior for Fl_Tree_Item's. e.g. /// \code -/// static void draw_item(Fl_Tree_Item *item, void *data) { -/// Fl_Tree *tree = (Fl_Tree*)data; -/// int X=item->label_x(), Y=item->label_y(), -/// W=item->label_w(), H=item->label_h(); -/// // Draw the background -/// fl_color(item->is_selected() ? tree->selection_color() : item->labelbgcolor()); -/// fl_rectf(X,Y,W,H); -/// // Draw text -/// fl_font(item->labelfont(), item->labelsize()); -/// fl_color(item->labelfgcolor()); -/// fl_draw("Some text", X+tree->labelmarginleft(),Y,W,H, FL_ALIGN_LEFT); -/// } -/// .. +/// static void draw_item(Fl_Tree_Item *item, void *data) { +/// Fl_Tree *tree = (Fl_Tree*)data; +/// int X=item->label_x(), Y=item->label_y(), +/// W=item->label_w(), H=item->label_h(); +/// // Draw the background +/// fl_color(item->is_selected() ? tree->selection_color() : item->labelbgcolor()); +/// fl_rectf(X,Y,W,H); +/// // Draw text +/// fl_font(item->labelfont(), item->labelsize()); +/// fl_color(item->labelfgcolor()); +/// fl_draw("Some text", X+tree->labelmarginleft(),Y,W,H, FL_ALIGN_LEFT); +/// } +/// .. /// int main() { /// Fl_Tree *tree = new Fl_Tree(0,0,100,100); /// tree->item_draw_callback(draw_item, (void*)tree); /// [..] /// \endcode -/// -/// Note: This only affects the drawing of item's labels; -/// it does not affect the drawing of widgets assigned with -/// Fl_Tree_Item::widget(). +/// \param[in] cb The callback to use +/// \param[in] data Optional item_draw_user_data() (default=NULL) +/// \note This only affects the drawing of item's labels, +/// it does not affect the drawing of widgets assigned with +/// Fl_Tree_Item::widget(). /// void Fl_Tree::item_draw_callback(Fl_Tree_Item_Draw_Callback *cb, void *data) { - _prefs.item_draw_callback(cb,data); + _prefs.item_draw_callback(cb,data); // no recalc_tree() -- changes don't affect item geometry } + /// Get the current item draw callback. Returns 0 if none. Fl_Tree_Item_Draw_Callback* Fl_Tree::item_draw_callback() const { return(_prefs.item_draw_callback()); } + /// Get the current item draw callback's user data. void* Fl_Tree::item_draw_user_data() const { return(_prefs.item_draw_user_data()); } + /// Invoke the configured item_draw_callback(). -// Do NOT call this if no item_draw_callback() was configured. +/// Do NOT call this if no item_draw_callback() was configured. void Fl_Tree::do_item_draw_callback(Fl_Tree_Item *o) const { _prefs.do_item_draw_callback(o); } #endif -/// See if \p item is currently displayed on-screen (visible within the widget). +/// See if \p 'item' is currently displayed on-screen (visible within the widget). +/// /// This can be used to detect if the item is scrolled off-screen. /// Checks to see if the item's vertical position is within the top and bottom -/// edges of the display window. This does NOT take into account the hide()/show() -/// or open()/close() status of the item. +/// edges of the display window. This does NOT take into account the hide() / show() +/// or open() / close() status of the item. /// /// \param[in] item The item to be checked. If NULL, first() is used. /// \returns 1 if displayed, 0 if scrolled off screen or no items are in tree. @@ -1867,8 +2427,8 @@ int Fl_Tree::displayed(Fl_Tree_Item *item) { return( (item->y() >= y()) && (item->y() <= (y()+h()-item->h())) ? 1 : 0); } -/// Adjust the vertical scroll bar so that \p item is visible -/// \p yoff pixels from the top of the Fl_Tree widget's display. +/// Adjust the vertical scroll bar so that \p 'item' is visible +/// \p 'yoff' pixels from the top of the Fl_Tree widget's display. /// /// For instance, yoff=0 will position the item at the top. /// @@ -1891,7 +2451,7 @@ void Fl_Tree::show_item(Fl_Tree_Item *item, int yoff) { redraw(); } -/// Adjust the vertical scroll bar to show \p item at the top +/// Adjust the vertical scroll bar to show \p 'item' at the top /// of the display IF it is currently off-screen (e.g. show_item_top()). /// If it is already on-screen, no change is made. /// @@ -1906,7 +2466,7 @@ void Fl_Tree::show_item(Fl_Tree_Item *item) { show_item_top(item); } -/// Adjust the vertical scrollbar so that \p item is at the top of the display. +/// Adjust the vertical scrollbar so that \p 'item' is at the top of the display. /// /// \param[in] item The item to be shown. If NULL, first() is used. /// @@ -1915,25 +2475,33 @@ void Fl_Tree::show_item_top(Fl_Tree_Item *item) { if (item) show_item(item, 0); } -/// Adjust the vertical scrollbar so that \p item is in the middle of the display. +/// Adjust the vertical scrollbar so that \p 'item' is in the middle of the display. /// /// \param[in] item The item to be shown. If NULL, first() is used. /// void Fl_Tree::show_item_middle(Fl_Tree_Item *item) { item = item ? item : first(); +#if FLTK_ABI_VERSION >= 10303 + if (item) show_item(item, (_tih/2)-(item->h()/2)); +#else if (item) show_item(item, (h()/2)-(item->h()/2)); +#endif } -/// Adjust the vertical scrollbar so that \p item is at the bottom of the display. +/// Adjust the vertical scrollbar so that \p 'item' is at the bottom of the display. /// /// \param[in] item The item to be shown. If NULL, first() is used. /// void Fl_Tree::show_item_bottom(Fl_Tree_Item *item) { item = item ? item : first(); +#if FLTK_ABI_VERSION >= 10303 + if (item) show_item(item, _tih-item->h()); +#else if (item) show_item(item, h()-item->h()); +#endif } -/// Displays \p item, scrolling the tree as necessary. +/// Displays \p 'item', scrolling the tree as necessary. /// \param[in] item The item to be displayed. If NULL, first() is used. /// void Fl_Tree::display(Fl_Tree_Item *item) { @@ -1943,19 +2511,17 @@ void Fl_Tree::display(Fl_Tree_Item *item) { /// Returns the vertical scroll position as a pixel offset. /// The position returned is how many pixels of the tree are scrolled off the top edge -/// of the screen. Example: A position of '3' indicates the top 3 pixels of -/// the tree are scrolled off the top edge of the screen. +/// of the screen. /// \see vposition(), hposition() /// int Fl_Tree::vposition() const { return((int)_vscroll->value()); } -/// Sets the vertical scroll offset to position \p pos. -/// The position is how many pixels of the tree are scrolled off the top edge -/// of the screen. Example: A position of '3' scrolls the top three pixels of -/// the tree off the top edge of the screen. -/// \param[in] pos The vertical position (in pixels) to scroll the browser to. +/// Sets the vertical scroll offset to position \p 'pos'. +/// The position is how many pixels of the tree are scrolled off the top edge +/// of the screen. +/// \param[in] pos The vertical position (in pixels) to scroll the browser to. /// void Fl_Tree::vposition(int pos) { if (pos < 0) pos = 0; @@ -1965,7 +2531,37 @@ void Fl_Tree::vposition(int pos) { redraw(); } -/// See if widget \p w is one of the Fl_Tree widget's scrollbars. +/// Returns the horizontal scroll position as a pixel offset. +/// The position returned is how many pixels of the tree are scrolled off the left edge +/// of the screen. +/// \see vposition(), hposition() +/// \note Must be using FLTK ABI 1.3.3 or higher for this to be effective. +/// +int Fl_Tree::hposition() const { +#if FLTK_ABI_VERSION >= 10303 + return((int)_hscroll->value()); +#else + return(0); +#endif +} + +/// Sets the horizontal scroll offset to position \p 'pos'. +/// The position is how many pixels of the tree are scrolled off the left edge +/// of the screen. +/// \param[in] pos The vertical position (in pixels) to scroll the browser to. +/// \note Must be using FLTK ABI 1.3.3 or higher for this to be effective. +/// +void Fl_Tree::hposition(int pos) { +#if FLTK_ABI_VERSION >= 10303 + if (pos < 0) pos = 0; + if (pos > _hscroll->maximum()) pos = (int)_hscroll->maximum(); + if (pos == _hscroll->value()) return; + _hscroll->value(pos); + redraw(); +#endif +} + +/// See if widget \p 'w' is one of the Fl_Tree widget's scrollbars. /// Use this to skip over the scrollbars when walking the child() array. Example: /// \code /// for ( int i=0; i<tree->children(); i++ ) { // walk children @@ -1976,12 +2572,18 @@ void Fl_Tree::vposition(int pos) { /// \endcode /// \param[in] w Widget to test /// \returns 1 if \p w is a scrollbar, 0 if not. +/// \todo should be const /// int Fl_Tree::is_scrollbar(Fl_Widget *w) { - return( ( w == _vscroll ) ? 1 : 0 ); +#if FLTK_ABI_VERSION >= 10303 + return( (w==_vscroll || w==_hscroll) ? 1 : 0 ); +#else + return( (w==_vscroll) ? 1 : 0 ); +#endif } -/// Gets the current size of the scrollbars' troughs, in pixels. +/// Gets the default size of scrollbars' troughs for this widget +/// in pixels. /// /// If this value is zero (default), this widget will use the global /// Fl::scrollbar_size() value as the scrollbar's width. @@ -1993,7 +2595,8 @@ int Fl_Tree::scrollbar_size() const { return(_scrollbar_size); } -/// Sets the pixel size of the scrollbars' troughs to the \p size, in pixels. +/// Sets the pixel size of the scrollbars' troughs to \p 'size' +/// for this widget, in pixels. /// /// Normally you should not need this method, and should use the global /// Fl::scrollbar_size(int) instead to manage the size of ALL @@ -2001,8 +2604,8 @@ int Fl_Tree::scrollbar_size() const { /// has a consistent UI, is the default behavior, and is normally /// what you want. /// -/// Only use THIS method if you really need to override the global -/// scrollbar size. The need for this should be rare. +/// Only use THIS method if you really need to override just this +/// widget instance's scrollbar size. (The need for this should be rare.) /// /// Setting \p size to the special value of 0 causes the widget to /// track the global Fl::scrollbar_size(), which is the default. @@ -2017,15 +2620,37 @@ void Fl_Tree::scrollbar_size(int size) { if ( _vscroll->w() != scrollsize ) { _vscroll->resize(x()+w()-scrollsize, h(), scrollsize, _vscroll->h()); } +#if FLTK_ABI_VERSION >= 10303 + if ( _hscroll->h() != scrollsize ) { + _hscroll->resize(x(), y()+h()-scrollsize, _hscroll->w(), scrollsize); + } + // Changing scrollbar size affects _tiw/_tih + may affect scrollbar visibility + calc_dimensions(); +#endif } /// See if the vertical scrollbar is currently visible. /// \returns 1 if scrollbar visible, 0 if not. +/// int Fl_Tree::is_vscroll_visible() const { return(_vscroll->visible() ? 1 : 0); } -/// Do the callback for the item, setting the item and reason +/// See if the horizontal scrollbar is currently visible. +/// \returns 1 if scrollbar visible, 0 if not. +/// \note Must be using FLTK ABI 1.3.3 or higher for this to be effective. +/// +int Fl_Tree::is_hscroll_visible() const { +#if FLTK_ABI_VERSION >= 10303 + return(_hscroll->visible() ? 1 : 0); +#else + return 0; +#endif +} + +/// Do the callback for the specified \p 'item' using \p 'reason', +/// setting the callback_item() and callback_reason(). +/// void Fl_Tree::do_callback_for_item(Fl_Tree_Item* item, Fl_Tree_Reason reason) { callback_reason(reason); callback_item(item); @@ -2033,7 +2658,7 @@ void Fl_Tree::do_callback_for_item(Fl_Tree_Item* item, Fl_Tree_Reason reason) { } /// Sets the item that was changed for this callback. -/// Used internally to pass the item that invoked the callback. +/// Used internally to pass the item that invoked the callback. /// void Fl_Tree::callback_item(Fl_Tree_Item* item) { _callback_item = item; @@ -2082,8 +2707,7 @@ Fl_Tree_Reason Fl_Tree::callback_reason() const { * directly loaded into the tree view for inspection. * \param[in] prefs the Fl_Preferences database */ -void Fl_Tree::load(Fl_Preferences &prefs) -{ +void Fl_Tree::load(Fl_Preferences &prefs) { int i, j, n, pn = (int) strlen(prefs.path()); char *p; const char *path = prefs.path(); @@ -2131,13 +2755,30 @@ void Fl_Tree::fix_scrollbar_order() { Fl_Widget** a = (Fl_Widget**)array(); if (a[children()-1] != _vscroll) { int i,j; +#if FLTK_ABI_VERSION >= 10303 + for (i = j = 0; j < children(); j++) { + if (a[j] != _vscroll && a[j] != _hscroll ) a[i++] = a[j]; + } + a[i++] = _hscroll; + a[i++] = _vscroll; +#else for (i = j = 0; j < children(); j++) { if (a[j] != _vscroll) a[i++] = a[j]; } a[i++] = _vscroll; +#endif } } +/// Schedule tree to recalc the entire tree size. +/// \note Must be using FLTK ABI 1.3.3 or higher for this to be effective. +/// +void Fl_Tree::recalc_tree() { +#if FLTK_ABI_VERSION >= 10303 + _tree_w = _tree_h = -1; +#endif +} + // // End of "$Id$". // diff --git a/src/Fl_Tree_Item.cxx b/src/Fl_Tree_Item.cxx index 2bbbb107c..9c9c24678 100644 --- a/src/Fl_Tree_Item.cxx +++ b/src/Fl_Tree_Item.cxx @@ -35,9 +35,20 @@ static int event_inside(const int xywh[4]) { } /// Constructor. -/// Makes a new instance of Fl_Tree_Item using defaults from 'prefs'. +/// Makes a new instance of Fl_Tree_Item using defaults from \p 'prefs'. +/// \deprecated in 1.3.3 ABI -- use Fl_Tree_Item(Fl_Tree*) instead. /// Fl_Tree_Item::Fl_Tree_Item(const Fl_Tree_Prefs &prefs) { + _Init(prefs, 0); +} + +// Initialize the tree item +// Used by constructors +// +void Fl_Tree_Item::_Init(const Fl_Tree_Prefs &prefs, Fl_Tree *tree) { +#if FLTK_ABI_VERSION >= 10303 + _tree = tree; +#endif _label = 0; _labelfont = prefs.labelfont(); _labelsize = prefs.labelsize(); @@ -76,6 +87,15 @@ Fl_Tree_Item::Fl_Tree_Item(const Fl_Tree_Prefs &prefs) { #endif /*FLTK_ABI_VERSION*/ } +#if FLTK_ABI_VERSION >= 10303 +/// Constructor. +/// Makes a new instance of Fl_Tree_Item for \p 'tree'. +/// +Fl_Tree_Item::Fl_Tree_Item(Fl_Tree *tree) { + _Init(tree->_prefs, tree); +} +#endif + // DTOR Fl_Tree_Item::~Fl_Tree_Item() { if ( _label ) { @@ -89,6 +109,9 @@ Fl_Tree_Item::~Fl_Tree_Item() { /// Copy constructor. Fl_Tree_Item::Fl_Tree_Item(const Fl_Tree_Item *o) { +#if FLTK_ABI_VERSION >= 10303 + _tree = o->_tree; +#endif _label = o->label() ? strdup(o->label()) : 0; _labelfont = o->labelfont(); _labelsize = o->labelsize(); @@ -149,10 +172,13 @@ void Fl_Tree_Item::show_self(const char *indent) const { fflush(stdout); } -/// Set the label. Makes a copy of the name. +/// Set the label to \p 'name'. +/// Makes and manages an internal copy of \p 'name'. +/// void Fl_Tree_Item::label(const char *name) { if ( _label ) { free((void*)_label); _label = 0; } _label = name ? strdup(name) : 0; + recalc_tree(); // may change label geometry } /// Return the label. @@ -168,9 +194,11 @@ const Fl_Tree_Item *Fl_Tree_Item::child(int index) const { /// Clear all the children for this item. void Fl_Tree_Item::clear_children() { _children.clear(); + recalc_tree(); // may change tree geometry } -/// Return the index of the immediate child of this item that has the label 'name'. +/// Return the index of the immediate child of this item +/// that has the label \p 'name'. /// /// \returns index of found item, or -1 if not found. /// @@ -187,7 +215,8 @@ int Fl_Tree_Item::find_child(const char *name) { return(-1); } -/// Find child item by descending array of names. Does not include self in search. +/// Find child item by descending array \p 'arr' of names. +/// Does not include self in search. /// Only Fl_Tree should need this method. /// /// \returns item, or 0 if not found @@ -207,7 +236,8 @@ const Fl_Tree_Item *Fl_Tree_Item::find_child_item(char **arr) const { return(0); } -/// Find child item by descending array of names. Does not include self in search. +/// Find child item by descending array \p 'arr' of names. +/// Does not include self in search. /// Only Fl_Tree should need this method. Use Fl_Tree::find_item() instead. /// /// \returns item, or 0 if not found @@ -227,7 +257,8 @@ Fl_Tree_Item *Fl_Tree_Item::find_child_item(char **arr) { return(0); } -/// Find item by descending array of \p names. Includes self in search. +/// Find item by descending array of \p 'names'. +/// Includes self in search. /// Only Fl_Tree should need this method. Use Fl_Tree::find_item() instead. /// /// \returns item, or 0 if not found @@ -244,7 +275,8 @@ const Fl_Tree_Item *Fl_Tree_Item::find_item(char **names) const { return(0); } -/// Find item by descending array of \p names. Includes self in search. +/// Find item by descending array of \p 'names'. +/// Includes self in search. /// Only Fl_Tree should need this method. /// /// \returns item, or 0 if not found @@ -261,7 +293,7 @@ Fl_Tree_Item *Fl_Tree_Item::find_item(char **names) { return(0); } -/// Find the index number for the specified 'item' +/// Find the index number for the specified \p 'item' /// in the current item's list of children. /// /// \returns the index, or -1 if not found. @@ -275,12 +307,18 @@ int Fl_Tree_Item::find_child(Fl_Tree_Item *item) { return(-1); } -/// Add a new child to this item with the name 'new_label', with defaults from 'prefs'. +/// Add a new child to this item with the name \p 'new_label' +/// and defaults from \p 'prefs'. /// An internally managed copy is made of the label string. /// Adds the item based on the value of prefs.sortorder(). /// Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs, const char *new_label) { +#if FLTK_ABI_VERSION >= 10303 + Fl_Tree_Item *item = new Fl_Tree_Item(_tree); +#else Fl_Tree_Item *item = new Fl_Tree_Item(prefs); +#endif + recalc_tree(); // may change tree geometry item->label(new_label); item->_parent = this; switch ( prefs.sortorder() ) { @@ -314,7 +352,7 @@ Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs, const char *new_labe return(item); } -/// Descend into the path specified by \p arr, and add a new child there. +/// Descend into the path specified by \p 'arr', and add a new child there. /// Should be used only by Fl_Tree's internals. /// Adds the item based on the value of prefs.sortorder(). /// \returns the item added. @@ -327,6 +365,7 @@ Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs, char **arr) { } else { item = (Fl_Tree_Item*)child(t); } + recalc_tree(); // may change tree geometry if ( *(arr+1) ) { // descend? return(item->add(prefs, arr+1)); } else { @@ -334,18 +373,24 @@ Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs, char **arr) { } } -/// Insert a new item into current item's children at a specified position. +/// Insert a new item named \p 'new_label' into current item's +/// children at a specified position \p 'pos'. /// \returns the new item inserted. /// Fl_Tree_Item *Fl_Tree_Item::insert(const Fl_Tree_Prefs &prefs, const char *new_label, int pos) { +#if FLTK_ABI_VERSION >= 10303 + Fl_Tree_Item *item = new Fl_Tree_Item(_tree); +#else Fl_Tree_Item *item = new Fl_Tree_Item(prefs); +#endif item->label(new_label); item->_parent = this; _children.insert(pos, item); + recalc_tree(); // may change tree geometry return(item); } -/// Insert a new item above this item. +/// Insert a new item named \p 'new_label' above this item. /// \returns the new item inserted, or 0 if an error occurred. /// Fl_Tree_Item *Fl_Tree_Item::insert_above(const Fl_Tree_Prefs &prefs, const char *new_label) { @@ -361,21 +406,22 @@ Fl_Tree_Item *Fl_Tree_Item::insert_above(const Fl_Tree_Prefs &prefs, const char return(0); } -/// Remove child by item. -/// \returns 0 if removed, -1 if item not an immediate child. +/// Remove \p 'item' from the current item's children. +/// \returns 0 if removed, -1 if item not an immediate child. /// int Fl_Tree_Item::remove_child(Fl_Tree_Item *item) { for ( int t=0; t<children(); t++ ) { if ( child(t) == item ) { item->clear_children(); _children.remove(t); + recalc_tree(); // may change tree geometry return(0); } } return(-1); } -/// Remove immediate child (and its children) by its label 'name'. +/// Remove immediate child (and its children) by its label \p 'name'. /// \returns 0 if removed, -1 if not found. /// int Fl_Tree_Item::remove_child(const char *name) { @@ -383,6 +429,7 @@ int Fl_Tree_Item::remove_child(const char *name) { if ( child(t)->label() ) { if ( strcmp(child(t)->label(), name) == 0 ) { _children.remove(t); + recalc_tree(); // may change tree geometry return(0); } } @@ -390,30 +437,23 @@ int Fl_Tree_Item::remove_child(const char *name) { return(-1); } -/// Swap two of our children, given two child index values. -/// Use this eg. for sorting. -/// -/// This method is FAST, and does not involve lookups. -/// +/// Swap two of our children, given two child index values \p 'ax' and \p 'bx'. +/// Use e.g. for sorting.<br> +/// This method is FAST, and does not involve lookups.<br> /// No range checking is done on either index value. /// -/// \returns -/// - 0 : OK -/// - -1 : failed: 'a' or 'b' is not our immediate child -/// void Fl_Tree_Item::swap_children(int ax, int bx) { _children.swap(ax, bx); } -/// Swap two of our children, given item pointers. -/// Use this eg. for sorting. +/// Swap two of our immediate children, given item pointers. +/// Use e.g. for sorting. /// -/// This method is SLOW because it involves linear lookups. +/// This method is SLOW because it involves linear lookups.<br> /// For speed, use swap_children(int,int) instead. -/// /// \returns /// - 0 : OK -/// - -1 : failed: 'a' or 'b' is not our immediate child +/// - -1 : failed: item \p 'a' or \p 'b' is not our child. /// int Fl_Tree_Item::swap_children(Fl_Tree_Item *a, Fl_Tree_Item *b) { int ax = -1, bx = -1; @@ -470,28 +510,31 @@ void Fl_Tree_Item::draw_vertical_connector(int x, int y1, int y2, const Fl_Tree_ } } -/// Find the item that the last event was over. -/// -/// Returns the item if it is visible, and mouse is over it. -/// Works even if widget deactivated. -/// Use event_on_collapse_icon() to determine if collapse button was pressed. -/// -/// \returns const visible item under the event if found, or 0 if none. -/// -const Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs) const { +// Internal +// Find the item that the last event was over. +// If \p 'yonly' is 1, only check event's y value, don't care about x. +// +const Fl_Tree_Item *Fl_Tree_Item::find_clicked_(const Fl_Tree_Prefs &prefs, int yonly) const { if ( ! is_visible() ) return(0); if ( is_root() && !prefs.showroot() ) { // skip event check if we're root but root not being shown } else { // See if event is over us - if ( event_inside(_xywh) ) { // event within this item? - return(this); // found + if ( yonly ) { + if ( Fl::event_y() >= _xywh[1] && + Fl::event_y() <= (_xywh[1]+_xywh[3]) ) { + return(this); + } + } else { + if ( event_inside(_xywh) ) { // event within this item? + return(this); // found + } } } if ( is_open() ) { // open? check children of this item for ( int t=0; t<children(); t++ ) { const Fl_Tree_Item *item; - if ( ( item = _children[t]->find_clicked(prefs) ) != NULL) { // check child and its descendents + if ( (item = _children[t]->find_clicked(prefs, yonly)) != NULL) { // check child and its descendents return(item); // found? } } @@ -499,34 +542,24 @@ const Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs) const return(0); } -/// Non-const version of the above. /// Find the item that the last event was over. +/// There is both a const and non-const version of this method. /// -/// Returns the item if it is visible, and mouse is over it. -/// Works even if widget deactivated. -/// Use event_on_collapse_icon() to determine if collapse button was pressed. +/// Returns the item if it is visible, and mouse is over it. +/// Works even if widget deactivated. +/// Use event_on_collapse_icon() to determine if collapse button was pressed. /// -/// \returns the visible item under the event if found, or 0 if none. +/// If \a yonly is set, only the mouse Y position is checked. /// -Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs) { - if ( ! is_visible() ) return(0); - if ( is_root() && !prefs.showroot() ) { - // skip event check if we're root but root not being shown - } else { - // See if event is over us - if ( event_inside(_xywh) ) { // event within this item? - return(this); // found - } - } - if ( is_open() ) { // open? check children of this item - for ( int t=0; t<children(); t++ ) { - Fl_Tree_Item *item; - if ( ( item = _children[t]->find_clicked(prefs) ) != NULL ) { // check child and its descendents - return(item); // found? - } - } - } - return(0); +/// \returns const visible item under the event if found, or 0 if none. +/// +const Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs, int yonly) const { + return(find_clicked_(prefs, yonly)); +} + +/// A const version of Fl_Tree_Item::find_clicked() +Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs, int yonly) { + return((Fl_Tree_Item*)find_clicked_(prefs, yonly)); } static void draw_item_focus(Fl_Boxtype B, Fl_Color fg, Fl_Color bg, int X, int Y, int W, int H) { @@ -570,7 +603,7 @@ static void draw_item_focus(Fl_Boxtype B, Fl_Color fg, Fl_Color bg, int X, int Y } /// Return the item's 'visible' height. -/// Doesn't include linespacing(); prevents affecting eg. height of widget(). +/// Doesn't include linespacing(); prevents affecting e.g. height of widget(). /// int Fl_Tree_Item::calc_item_height(const Fl_Tree_Prefs &prefs) const { if ( ! is_visible() ) return(0); @@ -593,7 +626,235 @@ int Fl_Tree_Item::calc_item_height(const Fl_Tree_Prefs &prefs) const { return(H); } +#if FLTK_ABI_VERSION >= 10303 +/// Draw this item and its children. +/// +/// \param[in] X Horizontal position for item being drawn +/// \param[in,out] Y Vertical position for item being drawn, returns new position for next item +/// \param[in] W Recommended width of item +/// \param[in] itemfocus The tree's current focus item (if any) +/// \param[in,out] tree_item_xmax The tree's running xmax (right-most edge so far). +/// Mainly used by parent tree when render==0 to calculate tree's max width. +/// \param[in] lastchild Is this item the last child in a subtree? +/// \param[in] render Whether or not to render the item: +/// - 0 -- no rendering, just calculate size. +/// (used to calculate size of tree without doing drawing) +/// - 1 -- render the item as well as doing size calculations +/// +void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Tree_Item *itemfocus, + int &tree_item_xmax, int lastchild, int render) { + Fl_Tree_Prefs &prefs = _tree->_prefs; + if ( !is_visible() ) return; + int tree_top = _tree->_tiy; + int tree_bot = tree_top + _tree->_tih; + int H = calc_item_height(prefs); // height of item + int H2 = H + prefs.linespacing(); // height of item with line spacing + + // Update the xywh of this item + _xywh[0] = X; + _xywh[1] = Y; + _xywh[2] = W; + _xywh[3] = H; + + // Determine collapse icon's xywh + // Note: calculate collapse icon's xywh for possible mouse click detection. + // We don't care about items clipped off the viewport; they won't get mouse events. + // + int item_y_center = Y+(H/2); + _collapse_xywh[2] = prefs.openicon()->w(); + int &icon_w = _collapse_xywh[2]; + _collapse_xywh[0] = X + (icon_w + prefs.connectorwidth())/2 - 3; + int &icon_x = _collapse_xywh[0]; + _collapse_xywh[1] = item_y_center - (prefs.openicon()->h()/2); + int &icon_y = _collapse_xywh[1]; + _collapse_xywh[3] = prefs.openicon()->h(); + + // Horizontal connector values + // Must calculate these even if(clipped) because 'draw children' code (below) + // needs hconn_x_center value. (Otherwise, these calculations could be 'clipped') + // + int hconn_x = X+icon_w/2-1; + int hconn_x2 = hconn_x + prefs.connectorwidth(); + int hconn_x_center = X + icon_w + ((hconn_x2 - (X + icon_w)) / 2); + int cw1 = icon_w+prefs.connectorwidth()/2, cw2 = prefs.connectorwidth(); + int conn_w = cw1>cw2 ? cw1 : cw2; + + // Background xywh + int &bg_x = _label_xywh[0] = X+(icon_w/2-1+conn_w); + int &bg_y = _label_xywh[1] = Y; + int &bg_w = _label_xywh[2] = _tree->_tix + _tree->_tiw - bg_x; + int &bg_h = _label_xywh[3] = H; + + // Usericon position + int uicon_x = bg_x + ( (usericon() || prefs.usericon()) ? prefs.usericonmarginleft() : 0); + int uicon_w = usericon() ? usericon()->w() : prefs.usericon() ? prefs.usericon()->w() : 0; + + // Label position + int label_x = uicon_x + uicon_w + (_label ? prefs.labelmarginleft() : 0); + + // Begin calc of this item's max width.. + // It might not even be visible, so start at zero. + // + int ixmax = 0; + + // Recalc widget position + // Do this whether clipped or not, so that when scrolled, + // the widgets move to appropriate 'offscreen' positions + // (so that they don't get mouse events, etc) + // + if ( widget() ) { + int wx = label_x; + int wy = bg_y; + int ww = widget()->w(); // use widget's width + int wh = (prefs.item_draw_mode() & FL_TREE_ITEM_HEIGHT_FROM_WIDGET) + ? widget()->h() : H; + if ( _label && + (prefs.item_draw_mode() & FL_TREE_ITEM_DRAW_LABEL_AND_WIDGET) ) { + fl_font(_labelfont, _labelsize); // fldescent() needs this + int lw=0, lh=0; + fl_measure(_label,lw,lh); // get box around text (including white space) + wx += (lw + prefs.widgetmarginleft()); + } + if ( widget()->x() != wx || widget()->y() != wy || + widget()->w() != ww || widget()->h() != wh ) { + widget()->resize(wx,wy,ww,wh); // we'll handle redraw below + } + } + char clipped = ((Y+H) < tree_top) || (Y>tree_bot) ? 1 : 0; + if (!render) clipped = 0; // NOT rendering? Then don't clip, so we calc unclipped items + char drawthis = ( is_root() && prefs.showroot() == 0 ) ? 0 : 1; + if ( !clipped ) { + Fl_Color fg = is_selected() ? fl_contrast(_labelfgcolor, _tree->selection_color()) + : is_active() ? _labelfgcolor + : fl_inactive(_labelfgcolor); + Fl_Color bg = is_selected() ? is_active() ? _tree->selection_color() + : fl_inactive(_tree->selection_color()) + : _labelbgcolor == 0xffffffff ? _tree->color() // transparent bg? + : _labelbgcolor; + // See if we should draw this item + // If this item is root, and showroot() is disabled, don't draw. + // 'clipped' is an optimization to prevent drawing anything offscreen. + // + if ( drawthis ) { // draw this item at all? + if ( (_tree->damage() & ~FL_DAMAGE_CHILD) || !render ) { // non-child damage? + // Draw connectors + if ( render && prefs.connectorstyle() != FL_TREE_CONNECTOR_NONE ) { + // Horiz connector between center of icon and text + // if this is root, the connector should not dangle in thin air on the left + if (is_root()) draw_horizontal_connector(hconn_x_center, hconn_x2, item_y_center, prefs); + else draw_horizontal_connector(hconn_x, hconn_x2, item_y_center, prefs); + // Small vertical line down to children + if ( has_children() && is_open() ) + draw_vertical_connector(hconn_x_center, item_y_center, Y+H2, prefs); + // Connectors for last child + if ( !is_root() ) { + if ( lastchild ) draw_vertical_connector(hconn_x, Y, item_y_center, prefs); + else draw_vertical_connector(hconn_x, Y, Y+H2, prefs); + } + } + // Draw collapse icon + if ( render && has_children() && prefs.showcollapse() ) { + // Draw icon image + if ( is_open() ) { + prefs.closeicon()->draw(icon_x,icon_y); + } else { + prefs.openicon()->draw(icon_x,icon_y); + } + } + // Background for this item + // Draw bg only if different from tree's bg + if ( render && (bg != _tree->color() || is_selected()) ) { + if ( is_selected() ) { // Selected? Use selectbox() style + fl_draw_box(prefs.selectbox(),bg_x,bg_y,bg_w,bg_h,bg); + } else { // Not Selected? use plain filled rectangle + fl_color(bg); + fl_rectf(bg_x,bg_y,bg_w,bg_h); + } + if ( widget() ) widget()->damage(FL_DAMAGE_ALL); // if there's a child widget, we just damaged it + } + // Draw user icon (if any) + if ( render && usericon() ) { + // Item has user icon? Use it + int uicon_y = item_y_center - (usericon()->h() >> 1); + usericon()->draw(uicon_x,uicon_y); + } else if ( render && prefs.usericon() ) { + // Prefs has user icon? Use it + int uicon_y = item_y_center - (prefs.usericon()->h() >> 1); + prefs.usericon()->draw(uicon_x,uicon_y); + } + // Draw label + if ( _label && + ( !widget() || + (prefs.item_draw_mode() & FL_TREE_ITEM_DRAW_LABEL_AND_WIDGET) ) ) { + if ( render ) { + fl_color(fg); + fl_font(_labelfont, _labelsize); + } + int label_y = Y+(H/2)+(_labelsize/2)-fl_descent()/2; + + int lw=0, lh=0; + fl_measure(_label, lw, lh); // get box around text (including white space) + if ( render ) fl_draw(_label, label_x, label_y); + ixmax = label_x + lw; // update max width of drawn item + } + } // end non-child damage + // Draw child FLTK widget? + if ( widget() ) { + if (render) + _tree->draw_child(*widget()); // let group handle drawing child + if ( widget()->label() && render ) + _tree->draw_outside_label(*widget()); // label too + ixmax = widget()->x() + widget()->w(); // update max width of widget + } + // Draw focus box around item's bg last + if ( render && + this == itemfocus && + Fl::visible_focus() && + Fl::focus() == _tree && + prefs.selectmode() != FL_TREE_SELECT_NONE ) { + draw_item_focus(FL_NO_BOX,fg,bg,bg_x+1,bg_y+1,bg_w-1,bg_h-1); + } + } // end drawthis + } // end clipped + if ( drawthis ) Y += H2; // adjust Y (even if clipped) + // Manage tree_item_xmax + if ( ixmax > tree_item_xmax ) + tree_item_xmax = ixmax; + // Draw child items (if any) + if ( has_children() && is_open() ) { + int child_x = drawthis ? (hconn_x_center - (icon_w/2) + 1) // offset children to right, + : X; // unless didn't drawthis + int child_w = W - (child_x-X); + int child_y_start = Y; + for ( int t=0; t<children(); t++ ) { + int lastchild = ((t+1)==children()) ? 1 : 0; + _children[t]->draw(child_x, Y, child_w, itemfocus, tree_item_xmax, lastchild, render); + } + if ( has_children() && is_open() ) { + Y += prefs.openchild_marginbottom(); // offset below open child tree + } + if ( ! lastchild ) { + // Special 'clipped' calculation. (intentional variable shadowing) + int clipped = ((child_y_start < tree_top) && (Y < tree_top)) || + ((child_y_start > tree_bot) && (Y > tree_bot)); + if (render && !clipped ) + draw_vertical_connector(hconn_x, child_y_start, Y, prefs); + } + } +} + +#else + /// Draw this item and its children. +/// +/// \param[in] X Horizontal position for item being drawn +/// \param[in,out] Y Vertical position for item being drawn, returns new position for next item +/// \param[in] W Recommended width of item +/// \param[in] tree The parent tree +/// \param[in] itemfocus The tree's current focus item (if any) +/// \param[in] prefs The tree's preferences +/// \param[in] lastchild Is this item the last child in a subtree? +/// void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Widget *tree, Fl_Tree_Item *itemfocus, const Fl_Tree_Prefs &prefs, int lastchild) { @@ -802,8 +1063,9 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Widget *tree, } } } +#endif -/// Was the event on the 'collapse' button? +/// Was the event on the 'collapse' button of this item? /// int Fl_Tree_Item::event_on_collapse_icon(const Fl_Tree_Prefs &prefs) const { if ( is_visible() && is_active() && has_children() && prefs.showcollapse() ) { @@ -813,7 +1075,7 @@ int Fl_Tree_Item::event_on_collapse_icon(const Fl_Tree_Prefs &prefs) const { } } -/// Was event on the label()? +/// Was event on the label() of this item? /// int Fl_Tree_Item::event_on_label(const Fl_Tree_Prefs &prefs) const { if ( is_visible() && is_active() ) { @@ -852,6 +1114,7 @@ void Fl_Tree_Item::open() { for ( int t=0; t<_children.total(); t++ ) { _children[t]->show_widgets(); } + recalc_tree(); // may change tree geometry } /// Close this item and all its children. @@ -861,12 +1124,14 @@ void Fl_Tree_Item::close() { for ( int t=0; t<_children.total(); t++ ) { _children[t]->hide_widgets(); } + recalc_tree(); // may change tree geometry } /// Returns how many levels deep this item is in the hierarchy. /// /// For instance; root has a depth of zero, and its immediate children -/// would have a depth of 1, and so on. +/// would have a depth of 1, and so on. Use e.g. for determining the +/// horizontal indent of this item during drawing. /// int Fl_Tree_Item::depth() const { int count = 0; @@ -914,7 +1179,8 @@ Fl_Tree_Item *Fl_Tree_Item::next() { /// This method can be used to walk the tree backwards. /// For an example of how to use this method, see Fl_Tree::last(). /// -/// \returns the previous item in the tree, or 0 if there's no item above this one (hit the root). +/// \returns the previous item in the tree, +/// or 0 if there's no item above this one (hit the root). /// Fl_Tree_Item *Fl_Tree_Item::prev() { #if FLTK_ABI_VERSION >= 10301 @@ -965,7 +1231,7 @@ Fl_Tree_Item *Fl_Tree_Item::prev() { /// Return this item's next sibling. /// /// Moves to the next item below us at the same level (sibling). -/// Use this to move down the tree without moving deeper into the tree, +/// Use this to move down the tree without changing depth(). /// effectively skipping over this item's children/descendents. /// /// \returns item's next sibling, or 0 if none. @@ -988,7 +1254,7 @@ Fl_Tree_Item *Fl_Tree_Item::next_sibling() { /// Return this item's previous sibling. /// /// Moves to the previous item above us at the same level (sibling). -/// Use this to move up the tree without moving deeper into the tree. +/// Use this to move up the tree without changing depth(). /// /// \returns This item's previous sibling, or 0 if none. /// @@ -1006,7 +1272,7 @@ Fl_Tree_Item *Fl_Tree_Item::prev_sibling() { #endif /*FLTK_ABI_VERSION*/ } -/// Update our _prev_sibling and _next_sibling pointers to point to neighbors, +/// Update our _prev_sibling and _next_sibling pointers to point to neighbors /// given \p index as being our current position in the parent's item array. /// Call this whenever items in the array are added/removed/moved/swapped. /// @@ -1031,14 +1297,16 @@ void Fl_Tree_Item::update_prev_next(int index) { #endif /*FLTK_ABI_VERSION*/ } -/// Return the next visible item. (If this item has children and is closed, children are skipped) +/// Return the next open(), visible() item. +/// (If this item has children and is closed, children are skipped) /// /// This method can be used to walk the tree forward, skipping items -/// that are not currently visible to the user. +/// that are not currently open/visible to the user. /// -/// \returns the next visible item below us, or 0 if there's no more items. +/// \returns the next open() visible() item below us, +/// or 0 if there's no more items. /// -Fl_Tree_Item *Fl_Tree_Item::next_displayed(Fl_Tree_Prefs &prefs) { +Fl_Tree_Item *Fl_Tree_Item::next_visible(Fl_Tree_Prefs &prefs) { Fl_Tree_Item *item = this; while ( 1 ) { item = item->next(); @@ -1048,14 +1316,22 @@ Fl_Tree_Item *Fl_Tree_Item::next_displayed(Fl_Tree_Prefs &prefs) { } } -/// Return the previous visible item. (If this item above us has children and is closed, its children are skipped) +/// Same as next_visible(). +/// \deprecated in 1.3.3 ABI for confusing name, use next_visible() +Fl_Tree_Item *Fl_Tree_Item::next_displayed(Fl_Tree_Prefs &prefs) { + return next_visible(prefs); +} + +/// Return the previous open(), visible() item. +/// (If this item above us has children and is closed, its children are skipped) /// /// This method can be used to walk the tree backward, -/// skipping items that are not currently visible to the user. +/// skipping items that are not currently open/visible to the user. /// -/// \returns the previous visible item above us, or 0 if there's no more items. +/// \returns the previous open() visible() item above us, +/// or 0 if there's no more items. /// -Fl_Tree_Item *Fl_Tree_Item::prev_displayed(Fl_Tree_Prefs &prefs) { +Fl_Tree_Item *Fl_Tree_Item::prev_visible(Fl_Tree_Prefs &prefs) { Fl_Tree_Item *c = this; while ( c ) { c = c->prev(); // previous item @@ -1075,11 +1351,17 @@ Fl_Tree_Item *Fl_Tree_Item::prev_displayed(Fl_Tree_Prefs &prefs) { return(0); // hit end: no more items } -/// Returns if item and all its parents are visible. -/// Also takes into consideration if any parent is close()ed. +/// Same as prev_visible(). +/// \deprecated in 1.3.3 ABI for confusing name, use prev_visible() +/// +Fl_Tree_Item *Fl_Tree_Item::prev_displayed(Fl_Tree_Prefs &prefs) { + return prev_visible(prefs); +} + +/// See if item and all its parents are open() and visible(). /// \returns -/// 1 -- item and its parents are visible/open() -/// 0 -- item (or parents) invisible or close()ed. +/// 1 -- item and its parents are open() and visible() +/// 0 -- item (or one of its parents) are invisible or close()ed. /// int Fl_Tree_Item::visible_r() const { if ( !visible() ) return(0); @@ -1088,6 +1370,16 @@ int Fl_Tree_Item::visible_r() const { return(1); } +/// Call this when our geometry is changed. (Font size, label contents, etc) +/// Schedules tree to recalculate itself, as changes to us may affect tree +/// widget's scrollbar visibility and tab sizes. +/// +void Fl_Tree_Item::recalc_tree() { +#if FLTK_ABI_VERSION >= 10303 + _tree->recalc_tree(); +#endif +} + // // End of "$Id$". // diff --git a/test/tree.fl b/test/tree.fl index ebb1b1bf3..22b287740 100644 --- a/test/tree.fl +++ b/test/tree.fl @@ -1,5 +1,5 @@ # data file for the Fltk User Interface Designer (fluid) -version 1.0300 +version 1.0302 header_name {.h} code_name {.cxx} decl {\#include <stdio.h>} {public global @@ -8,6 +8,9 @@ decl {\#include <stdio.h>} {public global decl {\#include <FL/Fl.H>} {public global } +decl {\#include <FL/Fl_Tooltip.H>} {public global +} + decl {\#include <FL/Fl_Pixmap.H>} {public global } @@ -233,11 +236,17 @@ tree->add("Descending/Bbb"); tree->add("Descending/Yyy"); tree->add("Descending/Ccc"); -// Add 500 items in numerical order +// Add a long line to trigger horiz scrollbar tree->sortorder(FL_TREE_SORT_NONE); +tree->add("Long Line")->close(); +tree->add("Long Line/The quick brown fox jumped over the lazy dog. 0123456789"); +tree->add("Long Line/Longer Line")->close(); +tree->add("Long Line/Longer Line/The quick brown fox jumped over the lazy dog. ---------------- 0123456789"); + +// Add 500 items in numerical order for ( int t=0; t<500; t++ ) { static char s[80]; - sprintf(s, "500 Items/item %04d", t); + sprintf(s, "500 Items/item %04d", t+1); tree->add(s); } tree->close("500 Items"); // close the 500 items by default @@ -336,7 +345,7 @@ Function {} {open } { Fl_Window window { label tree open - xywh {5 44 1045 580} type Double visible + xywh {0 234 1045 580} type Double visible } { Fl_Group tree { label Tree @@ -367,7 +376,7 @@ tree->clear_changed();} open class Fl_Tree } {} Fl_Group {} {open - xywh {300 5 731 615} + xywh {350 5 681 615} code0 {o->resizable(0);} } { Fl_Box {} { @@ -393,7 +402,7 @@ tree->marginleft(val); tree->redraw();} tooltip {Changes the left margin for the tree widget} xywh {505 60 155 16} type Horizontal color 46 selection_color 1 labelsize 10 align 4 textsize 9 code0 {o->value(tree->marginleft());} - code1 {o->range(0.0, 100.0);} + code1 {o->range(0.0, 200.0);} code2 {o->step(1.0);} } Fl_Value_Slider marginbottom_slider { @@ -409,7 +418,7 @@ tree->redraw(); marginbottom_slider->deactivate(); // deactivate if this ABI feature is disabled marginbottom_slider->tooltip("DISABLED.\\n" "Set FLTK_ABI_VERSION to 10301 (or higher)\\n" - "to get this feature"); + "to enable this feature"); \#endif} tooltip {Changes the bottom margin for the tree Sets how far beyond bottom of tree you can scroll} xywh {505 80 155 16} type Horizontal color 46 selection_color 1 labelsize 10 align 4 textsize 9 @@ -462,9 +471,11 @@ tree->redraw(); widgetmarginleft_slider->deactivate(); widgetmarginleft_slider->tooltip("DISABLED.\\n" "Set FLTK_ABI_VERSION to 10301 (or higher)\\n" - "to get this feature"); + "to enable this feature"); \#endif} - tooltip {Changes the margin to the left of child FLTK widget()} xywh {505 160 155 16} type Horizontal color 46 selection_color 1 labelsize 10 align 4 textsize 9 + tooltip {Changes the margin to the left of child FLTK widget() +"Show label + widget" must be 'on' for this to take effect, i.e. +item_draw_mode(FL_TREE_ITEM_DRAW_LABEL_AND_WIDGET)} xywh {505 160 155 16} type Horizontal color 46 selection_color 1 labelsize 10 align 4 textsize 9 code0 {o->value(GetTreeWidgetMarginLeft()); // handle ABI feature} code1 {o->range(0.0, 100.0);} code2 {o->step(1.0);} @@ -580,7 +591,7 @@ switch ( collapseicons_chooser->value() ) { tree->showcollapse(0); break; }} - tooltip {Tests Fl_Tree::openicon() and Fl_Tree::closeicon()} xywh {520 225 140 21} down_box BORDER_BOX labelsize 12 textsize 11 + tooltip {Tests Fl_Tree::openicon(), Fl_Tree::closeicon() and Fl_Tree::showcollapse().} xywh {520 225 140 21} down_box BORDER_BOX labelsize 12 textsize 11 } { MenuItem {} { label Normal @@ -603,7 +614,7 @@ switch ( connectorstyle_chooser->value() ) { case 1: tree->connectorstyle(FL_TREE_CONNECTOR_DOTTED); break; case 2: tree->connectorstyle(FL_TREE_CONNECTOR_SOLID); break; }} - tooltip {Tests connectorstyle() bit flags} xywh {520 249 140 21} down_box BORDER_BOX labelsize 12 textsize 11 + tooltip {Tests Fl_Tree::connectorstyle() bit flags} xywh {520 249 140 21} down_box BORDER_BOX labelsize 12 textsize 11 code0 {switch (tree->connectorstyle()) { case FL_TREE_CONNECTOR_NONE: connectorstyle_chooser->value(0); break; case FL_TREE_CONNECTOR_DOTTED: connectorstyle_chooser->value(1); break; case FL_TREE_CONNECTOR_SOLID: connectorstyle_chooser->value(2); break; }} } { MenuItem {} { @@ -628,7 +639,11 @@ switch ( selectmode_chooser->value() ) { case 2: tree->selectmode(FL_TREE_SELECT_MULTI); break; // Multi default: tree->selectmode(FL_TREE_SELECT_SINGLE); break; // Single }} - tooltip {Sets how Fl_Tree handles mouse selection of tree items} xywh {520 273 140 21} down_box BORDER_BOX labelsize 12 textsize 11 + tooltip {Tests Fl_Tree::selectmode() +Sets how Fl_Tree handles mouse selection of tree items. + NONE -- Not selectable by keyboard/mouse + SINGLE -- Only one item at a time selectable by keyboard/mouse + MULTI -- Multiple items selectable} xywh {520 273 140 21} down_box BORDER_BOX labelsize 12 textsize 11 code0 {selectmode_chooser->value(2);} code1 {cb_selectmode_chooser(selectmode_chooser, (void*)0);} } { @@ -659,11 +674,13 @@ switch ( reselectmode_chooser->value() ) { reselectmode_chooser->deactivate(); // deactivate if this ABI feature is disabled reselectmode_chooser->tooltip("DISABLED.\\n" "Set FLTK_ABI_VERSION to 10301 (or higher)\\n" - "to get this feature"); + "to enable this feature"); window->redraw(); // deactivated \#endif} - tooltip {Enable 'reselect' events -These happen when mouse drags or multi-clicks an item} xywh {520 297 140 21} down_box BORDER_BOX labelsize 12 textsize 11 + tooltip {Tests Fl_Tree::item_reselect_mode(). +Enables 'reselect' events. +These happen when someone selects an item already selected +(mouse drags or multi-clicks)} xywh {520 297 140 21} down_box BORDER_BOX labelsize 12 textsize 11 code0 {reselectmode_chooser->value(1);} code1 {reselectmode_chooser->do_callback();} } { @@ -727,7 +744,7 @@ tree->visible_focus(onoff);} } Fl_Check_Button labelandwidget_radio { label {Show label + widget} - callback {\#if FLTK_ABI_VERSION >= 10301 + callback {\#if FLTK_ABI_VERSION >= 10303 // NEW int flags = tree->item_draw_mode(); if ( labelandwidget_radio->value() ) @@ -740,18 +757,20 @@ tree->redraw(); // OLD labelandwidget_radio->deactivate(); // deactivate if this ABI feature is disabled labelandwidget_radio->tooltip("DISABLED.\\n" - "Set FLTK_ABI_VERSION to 10301 (or higher)\\n" - "to get this feature"); + "Set FLTK_ABI_VERSION to 10303 (or higher)\\n" + "to enable this feature"); window->redraw(); // deactivated \#endif} - tooltip {Enables both label and widget() for display. -When enabled, widget should appear to the right of the item's label. By default, the widget() is shown in place of the item's label.} xywh {645 356 20 16} down_box DOWN_BOX labelsize 11 align 7 + tooltip {Tests Fl_Tree::item_draw_mode(FL_TREE_ITEM_DRAW_LABEL_AND_WIDGET) +Enables both label and widget() for display. +When enabled, widget should appear to the right of the item's label. +By default, the widget() is shown in place of the item's label.} xywh {645 356 20 16} down_box DOWN_BOX labelsize 11 align 7 code0 {labelandwidget_radio->value(0);} code1 {labelandwidget_radio->do_callback();} } Fl_Check_Button itemheightfromwidget_radio { label {Item h() from widget} - callback {\#if FLTK_ABI_VERSION >= 10301 + callback {\#if FLTK_ABI_VERSION >= 10303 // NEW int flags = tree->item_draw_mode(); if ( itemheightfromwidget_radio->value() ) @@ -764,11 +783,12 @@ tree->redraw(); // OLD itemheightfromwidget_radio->deactivate(); // deactivate if this ABI feature is disabled itemheightfromwidget_radio->tooltip("DISABLED.\\n" - "Set FLTK_ABI_VERSION to 10301 (or higher)\\n" - "to get this feature"); + "Set FLTK_ABI_VERSION to 10303 (or higher)\\n" + "to enable this feature"); window->redraw(); // deactivated \#endif} - tooltip {If enabled, item's height will track the widget()'s height. + tooltip {Tests Fl_Tree::item_draw_mode(FL_TREE_ITEM_HEIGHT_FROM_WIDGET) +If enabled, item's height will track the widget()'s height. When enabled, click 'ccc' or 'D1/D2' buttons to test.} xywh {645 371 20 16} down_box DOWN_BOX labelsize 11 align 7 code0 {itemheightfromwidget_radio->value(0);} code1 {itemheightfromwidget_radio->do_callback();} @@ -877,7 +897,8 @@ switch ( tree->item_pathname(pathname, sizeof(pathname), item) ) { case -1: fl_message("item_pathname() returned -1 (NOT FOUND)"); break; case -2: fl_message("item_pathname() returned -2 (STRING TOO LONG)"); break; }} - tooltip {Show the pathname for the selected item. Tests the Fl_Tree::item_pathname() method.} xywh {470 531 95 16} labelsize 9 + tooltip {Tests Fl_Tree::item_pathname() +Show the pathname for the selected item.} xywh {470 531 95 16} labelsize 9 } Fl_Button closeall_button { label {Close All} @@ -895,8 +916,8 @@ tree->redraw();} label {Clear All} callback {tree->clear(); tree->redraw();} - tooltip {Clears all items -Tests Fl_Tree::clear()} xywh {570 471 95 16} labelsize 9 + tooltip {Tests Fl_Tree::clear(). +Clears all items} xywh {570 471 95 16} labelsize 9 } Fl_Button testcallbackflag_button { label {Test Callback Flag} @@ -1021,7 +1042,9 @@ if ( ! count ) { } tree->redraw();} - tooltip {Changes the font for the selected items's labels. If none selected, all are changed. Tests Fl_Tree_Item::labelfont();} xywh {863 31 140 21} down_box BORDER_BOX labelsize 11 textsize 11 + tooltip {Tests Fl_Tree_Item::labelfont(); +Changes the font for the selected items's labels. +If none selected, all are changed.} xywh {863 31 140 21} down_box BORDER_BOX labelsize 11 textsize 11 code0 {o->value((int)tree->item_labelfont()); // get tree's current font, assign to chooser} } { MenuItem {} { @@ -1112,7 +1135,9 @@ if ( ! count ) { } tree->redraw();} - tooltip {Changes the font size of the selected items's labels. If none selected, all are changed. Tests Fl_Tree_Item::labelsize();} xywh {863 55 140 16} type Horizontal color 46 selection_color 1 labelsize 11 align 4 textsize 12 + tooltip {Tests Fl_Tree_Item::labelsize(); +Changes the font size of the selected items's labels. +If none selected, all are changed.} xywh {863 55 140 16} type Horizontal color 46 selection_color 1 labelsize 11 align 4 textsize 12 code0 {o->value(tree->item_labelsize());} code1 {o->range(5.0, 200.0);} code2 {o->step(1.0);} @@ -1289,6 +1314,20 @@ tree->redraw();} tree->redraw();} tooltip {Deselects all items in the tree} xywh {724 219 95 16} labelsize 9 } + Fl_Button nextselected_button { + label {next_selected()} + callback {printf("--- TEST next_selected():\\n"); +printf(" // Walk down the tree (forwards)\\n"); + for ( Fl_Tree_Item *i=tree->first_selected_item(); i; i=tree->next_selected_item(i, FL_Down) ) { + printf(" Selected item: %s\\n", i->label()?i->label():"<nolabel>"); + } + +printf(" // Walk up the tree (backwards)\\n"); + for ( Fl_Tree_Item *i=tree->last_selected_item(); i; i=tree->next_selected_item(i, FL_Up) ) { + printf(" Selected item: %s\\n", i->label()?i->label():"<nolabel>"); + }} + tooltip {Tests the Fl_Tree::next_selected() function} xywh {723 239 95 16} labelsize 9 + } Fl_Light_Button bbbselect_toggle { label { Select Bbb} callback {// Toggle select of just the Bbb item (not children) @@ -1354,19 +1393,19 @@ if ( !item) { } int onoff = rootselect2_toggle->value(); if ( onoff ) tree->select_all(item); // select /ROOT and its children -else tree->deselect_all(item); // deselect /ROOT and its children} +else tree->deselect_all(item); // deselect /ROOT and its children} selected tooltip {Toggle selection of the ROOT item and all children} xywh {914 219 95 16} selection_color 1 labelsize 9 } Fl_Box {} { label {Tree Fonts + Colors} - tooltip {These controls only affect the selected items. If no items are selected, all existing items in tree are modified.} xywh {695 298 335 244} box GTK_DOWN_BOX color 47 labelsize 12 align 1 + tooltip {These controls only affect the selected items. If no items are selected, all existing items in tree are modified.} xywh {695 298 335 186} box GTK_DOWN_BOX color 47 labelsize 12 align 1 } Fl_Choice labelfont_choice { label {labelfont()} callback {Fl_Font val = (Fl_Font)labelfont_choice->value(); tree->labelfont(val); window->redraw();} - tooltip {Sets the default font used for new items created. Does NOT affect existing items.} xywh {850 319 140 21} down_box BORDER_BOX labelsize 12 textsize 12 + tooltip {Sets the default font used for new items created. Does NOT affect existing items.} xywh {848 314 140 21} down_box BORDER_BOX labelsize 12 textsize 12 code0 {o->value((int)tree->labelfont()); // get tree's current font, assign to chooser} } { MenuItem {} { @@ -1440,7 +1479,7 @@ window->redraw();} callback {tree->labelsize((int)labelsize_slider->value()); window->redraw();} tooltip {Sets the font size for the tree's label(). -This is also the font size that will be used to draw the items IF their size hasn't been set with Fl_Tree_Item::labelsize() or Fl_Tree::item_labelsize()} xywh {850 343 140 16} type Horizontal color 46 selection_color 1 labelsize 12 align 4 textsize 12 +This is also the font size that will be used to draw the items IF their size hasn't been set with Fl_Tree_Item::labelsize() or Fl_Tree::item_labelsize()} xywh {848 338 140 16} type Horizontal color 46 selection_color 1 labelsize 12 align 4 textsize 12 code0 {o->value((int)tree->labelsize());} code1 {o->range(1.0, 50.0);} code2 {o->step(1.0);} @@ -1452,7 +1491,7 @@ This is also the font size that will be used to draw the items IF their size has tree->item_labelfont(val); tree->redraw();} tooltip {Sets the default font used for new items created. -.Also affects any items whose font has NOT specifically been set with item->labelfont().} xywh {850 363 140 21} down_box BORDER_BOX labelsize 12 textsize 12 +.Also affects any items whose font has NOT specifically been set with item->labelfont().} xywh {848 358 140 21} down_box BORDER_BOX labelsize 12 textsize 12 code0 {o->value((int)tree->item_labelfont());} } { MenuItem {} { @@ -1526,7 +1565,7 @@ tree->redraw();} callback {tree->item_labelsize((int)item_labelsize_slider->value()); tree->redraw();} tooltip {Sets the default font size used for new items created. -.Also affects any items whose font size has NOT specifically been set with item->labelsize().} xywh {850 388 140 16} type Horizontal color 46 selection_color 1 labelsize 12 align 4 textsize 12 +.Also affects any items whose font size has NOT specifically been set with item->labelsize().} xywh {848 383 140 16} type Horizontal color 46 selection_color 1 labelsize 12 align 4 textsize 12 code0 {o->value((int)tree->item_labelsize());} code1 {o->range(1.0, 50.0);} code2 {o->step(1.0);} @@ -1540,7 +1579,7 @@ labelcolor_button->color(val); // update modified color to button tree->labelcolor(val); window->redraw(); // affects window (tree's label is outside tree's area)} tooltip {Changes Fl_Tree::labelcolor(). -This affects the text color of the widget's label.} xywh {815 458 16 16} box DOWN_BOX labelsize 11 align 7 +This affects the text color of the widget's label.} xywh {813 414 16 16} box DOWN_BOX labelsize 11 align 7 code0 {o->color(tree->labelcolor());} } Fl_Button color_button { @@ -1552,7 +1591,7 @@ tree->color(val); UpdateColorChips(); tree->redraw();} tooltip {Changes Fl_Tree::color(). -This affects the background color of the widget. It also affects the bg color of newly created items *if* Fl_Tree::item_labelbgcolor() hasn't been changed.} xywh {815 477 16 16} box DOWN_BOX labelsize 11 align 7 +This affects the background color of the widget. It also affects the bg color of newly created items *if* Fl_Tree::item_labelbgcolor() hasn't been changed.} xywh {813 433 16 16} box DOWN_BOX labelsize 11 align 7 code0 {o->color(tree->color());} } Fl_Button selection_color_button { @@ -1563,7 +1602,7 @@ selection_color_button->color(val); // update modified color to button tree->selection_color(val); tree->redraw();} tooltip {Sets the Fl_Tree::selection_color(). -This affects the item's colors when they're selected.} xywh {815 496 16 16} box DOWN_BOX labelsize 11 align 7 +This affects the item's colors when they're selected.} xywh {813 452 16 16} box DOWN_BOX labelsize 11 align 7 code0 {o->color(tree->selection_color());} } Fl_Button item_labelfgcolor_button { @@ -1573,7 +1612,7 @@ if ( EditColor(val) == 0 ) return; // Let user edit color. (return if they hit tree->item_labelfgcolor(val); // apply modified color to tree item_labelfgcolor_button->color(val); // update modified color to button tree->redraw();} - tooltip {Sets the default label fg color for newly created items.} xywh {975 458 16 16} box DOWN_BOX labelsize 12 align 7 + tooltip {Sets the default label fg color for newly created items.} xywh {973 414 16 16} box DOWN_BOX labelsize 12 align 7 code0 {o->color(tree->item_labelfgcolor());} } Fl_Button item_labelbgcolor_button { @@ -1583,7 +1622,7 @@ if ( EditColor(val) == 0 ) return; // Let user edit color. (return if they hit tree->item_labelbgcolor(val); // apply modified color to tree item_labelbgcolor_button->color(val); // update modified color to button tree->redraw();} - tooltip {Sets the default label bg color for newly created items. When set, this overrides the default behavior of using Fl_Tree::color().} xywh {975 477 16 16} box DOWN_BOX labelsize 12 align 7 + tooltip {Sets the default label bg color for newly created items. When set, this overrides the default behavior of using Fl_Tree::color().} xywh {973 433 16 16} box DOWN_BOX labelsize 12 align 7 code0 {item_labelbgcolor_button->color(tree->item_labelbgcolor());} } Fl_Button x_item_labelbgcolor_button { @@ -1591,7 +1630,7 @@ tree->redraw();} callback {tree->item_labelbgcolor(0xffffffff); UpdateColorChips(); tree->redraw();} - tooltip {Make the bgcolor 'transparent' (0xffffffff)} xywh {995 477 16 16} labelsize 10 align 16 + tooltip {Make the bgcolor 'transparent' (0xffffffff)} xywh {993 433 16 16} labelsize 10 align 16 } Fl_Button testsuggs_button { label {Test Suggestions} @@ -1620,23 +1659,50 @@ tree->redraw();} " 3) Disable same, item labels should disappear,\\n" " showing the widgets in their place.\\n" "\\n" -" COLORS\\n" -" ======\\n" -" 1) Start program\\n" -" 2) Change 'Tree Fonts+Colors' -> color()\\n" -" 3) Entire tree's background color will change, including items.\\n" -" 4) Change the 'Tree Fonts + Colors -> item_labelbgcolor()'\\n" -" 6) Click the '111' item to select it.\\n" -" 7) Click 'Test Operations -> Insert Above'\\n" -" New items should appear above the selected item using the new color.\\n" -" This color will be different from the background color.\\n" -" 8) Change the 'Tree Fonts+Colors' -> color()\\n" -" The entire tree's bg should change, except the new items.\\n" -" 9) Click the Tree Fonts+Colors -> item_labelbgcolor() 'X' button.\\n" -" This resets item_labelbgcolor() to the default 'transparent' color (0xffffffff)\\n" -" 10) Again, click the 'Insert Above' button.\\n" -" New items will be created in the background color, and changing the color()\\n" -" should affect the new items too.\\n" +"COLORS\\n" +"======\\n" +" 1) Start program\\n" +" 2) Change 'Tree Fonts+Colors' -> color()\\n" +" 3) Entire tree's background color will change, including items.\\n" +" 4) Change the 'Tree Fonts + Colors -> item_labelbgcolor()'\\n" +" 6) Click the '111' item to select it.\\n" +" 7) Click 'Test Operations -> Insert Above'\\n" +" New items should appear above the selected item using the new color.\\n" +" This color will be different from the background color.\\n" +" 8) Change the 'Tree Fonts+Colors' -> color()\\n" +" The entire tree's bg should change, except the new items.\\n" +" 9) Click the Tree Fonts+Colors -> item_labelbgcolor() 'X' button.\\n" +" This resets item_labelbgcolor() to the default 'transparent' color (0xffffffff)\\n" +" 10) Again, click the 'Insert Above' button.\\n" +" New items will be created in the background color, and changing the color()\\n" +" should affect the new items too.\\n" +"\\n" +"SCROLLING\\n" +"=========\\n" +" 1) Open '500 items' and 'Long Line' so that both scrollbars appear:\\n" +" * The 'focus box' for the selected item should not be clipped\\n" +" horizontally by the vertical scrollbar.\\n" +" * Resizing the window horizontally should resize the focus box\\n" +" * Scrolling vertically/horizontally should show reveal all\\n" +" edges of the tree. One *exception* is the widget label\\n" +" to the right of the 'ccc button'; labels aren't part\\n" +" of the widget, and therefore don't affect scroll tabs\\n" +" 2) Scroll vertical scroller to the middle of the tree\\n" +" 3) Left click and drag up/down to extend the selection:\\n" +" * Selection should autoscroll if you drag off the top/bottom\\n" +" * Selection should work *even* if you drag horizontally\\n" +" off the window edge; moving up/down outside the window\\n" +" should continue to autoscroll\\n" +" 4) Click either of the the scrollbar tabs and drag:\\n" +" * Even if you drag off the scrollbar, the scrollbar\\n" +" tab should continue to move\\n" +" * Should continue to work if you drag off the window edge\\n" +" horizontally drag off the window.\\n" +" 5) Click 'Bbb' and hit 'Add 20,000', then position the\\n" +" 'ccc button' so it's partially obscured by a scrollbar tab:\\n" +" * Clicking the obscured button should work\\n" +" * Clicking on the tab over the button should not 'click through'\\n" +" to the button.\\n" ""; static Fl_Double_Window *helpwin = 0; @@ -1654,9 +1720,31 @@ if ( !helpwin ) { helpwin->end(); } helpwin->resizable(helpdisp); -helpwin->show();} selected +helpwin->show();} tooltip {Suggestions on how to do tests} xywh {935 554 95 16} labelsize 9 } + Fl_Value_Slider tree_scrollbar_size_slider { + label {Fl_Tree::scrollbar_size()} + callback {tree->scrollbar_size(tree_scrollbar_size_slider->value()); +tree->redraw();} + tooltip {Tests Fl_Tree::scrollbar_size() effects on tree clipping. +The value is normally 0, which causes Fl_Tree to use the global Fl::scrollbar_size() instead. +} xywh {835 499 180 16} type Horizontal color 46 selection_color 1 labelsize 11 align 4 textsize 9 + code0 {o->value(tree->scrollbar_size());} + code1 {o->range(0.0, 30.0);} + code2 {o->step(1.0);} + code3 {o->color(46); o->selection_color(FL_RED);} + } + Fl_Value_Slider scrollbar_size_slider { + label {Fl::scrollbar_size()} + callback {Fl::scrollbar_size(scrollbar_size_slider->value()); +tree->redraw();} + tooltip {Tests Fl::scrollbar_size() effects on tree clipping} xywh {835 519 180 16} type Horizontal color 46 selection_color 1 labelsize 11 align 4 textsize 9 + code0 {o->value(Fl::scrollbar_size());} + code1 {o->range(5.0, 30.0);} + code2 {o->step(1.0);} + code3 {o->color(46); o->selection_color(FL_RED);} + } } Fl_Box resizer_box { xywh {0 263 15 14} @@ -1673,6 +1761,8 @@ RebuildTree(); //Fl::scheme("gtk+"); +Fl_Tooltip::size(10); // small font for tooltips + window->resizable(tree); window->size_range(window->w(), window->h(), 0, 0); |
