FLTK logo

[Library] r10034 - /branches/branch-1.3 /branches/branch-1.3/src /branches/branch-1.3/test /branches/branch-1.3/FL

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 All Forums  |  Back to fltk.commit  ]
 
Previous Message ]Next Message ]

[Library] r10034 - /branches/branch-1.3 /branches/branch-1.3/src /branches/branch-1.3/test /branches/branch-1.3/FL [greg.ercolano] Dec 15, 2013  
 
 ------------------------------------------------------------------------
 r10034 | greg.ercolano | 2013-12-15 13:59:02 -0500 (Sun, 15 Dec 2013) | 53 lines
 Changed paths:
    M /branches/branch-1.3/CHANGES
    M /branches/branch-1.3/FL/Fl_Tree.H
    M /branches/branch-1.3/FL/Fl_Tree_Item.H
    M /branches/branch-1.3/FL/Fl_Tree_Prefs.H
    M /branches/branch-1.3/src/Fl_Tree.cxx
    M /branches/branch-1.3/src/Fl_Tree_Item.cxx
    M /branches/branch-1.3/test/tree.fl
 
 Adds horizontal scrollbar to Fl_Tree as an ABI 1.3.3 feature.
 
 ***************************************************************
 NOTE: You MUST uncomment the FLTK_ABI_VERSION in Enumerations.H
       to use these changes.
 ***************************************************************
 
 Also: separated tree size calculation from draw() code,
 so that one can cause the tree to recalculate immediately
 after making modifications to the tree by calling Fl_Tree::calc_tree().
 
 Numerous improvements to docs for the tree as well, enough
 to create a rather large diff.
 
 Large internal changes were needed to do this properly.
 The following was added to the CHANGES file:
 
 	- 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
 
 
 
 ------------------------------------------------------------------------
Index: branches/branch-1.3/src/Fl_Tree_Item.cxx
===================================================================
--- branches/branch-1.3/src/Fl_Tree_Item.cxx	(revision 10033)
+++ branches/branch-1.3/src/Fl_Tree_Item.cxx	(revision 10034)
@@ -35,9 +35,20 @@
 }
 
 /// 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 @@
 #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 @@
 
 /// 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 @@
   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 @@
 /// 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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   } 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 @@
   }
 }
 
-/// 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 @@
   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 @@
     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 @@
   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 @@
   }
 }
 
-/// 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,36 +542,26 @@
   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) {
   if (!Fl::visible_focus()) return;
   switch (B) {
@@ -570,7 +603,7 @@
 }
 
 /// 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 @@
   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 @@
     }
   }
 }
+#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 @@
   }
 }
 
-/// 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 @@
   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 @@
   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 @@
 /// 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 @@
 /// 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 @@
 /// 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 @@
 #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 @@
 #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 @@
   }
 }
 
-/// 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 @@
   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 @@
   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$".
 //
Index: branches/branch-1.3/src/Fl_Tree.cxx
===================================================================
--- branches/branch-1.3/src/Fl_Tree.cxx	(revision 10033)
+++ branches/branch-1.3/src/Fl_Tree.cxx	(revision 10034)
@@ -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 @@
   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 @@
   }
 }
 
-// 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 @@
 
 /// 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 @@
   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 @@
   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 @@
   // 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 @@
       //     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 @@
       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 @@
 	    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 @@
 		  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 @@
 
   // 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 @@
 	}
 	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 @@
       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 @@
   }
 }
 
+// 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 @@
       W += _prefs.openicon()->w();
     }
     int Ysave = Y;
-     
     fl_push_clip(cx,cy,cw,ch);
     {
       fl_font(_prefs.labelfont(), _prefs.labelsize());
@@ -509,16 +855,18 @@
   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 @@
   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
+/// \param[in] path The path to the item, e.g. "Flintsone/Fred".
+/// \returns The new item added, or 0 on error.
 ///
-/// \returns the child item created, 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 @@
   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 @@
   _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 @@
   }
 } 
 
-/// 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 @@
 /// \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 @@
   *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 @@
   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 @@
 /// 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 @@
   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.
+/// Return the previous item before \p 'item', or 0 if no more items.
 ///
-/// 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->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,18 +1202,16 @@
 
 /// 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).
+/// \returns Last item in the tree, or 0 if none (tree empty).
+/// \see first(), next(), last(), prev()
 ///
-/// \see first(),next(),last(),prev()
-///
 Fl_Tree_Item* Fl_Tree::last() {
   if ( ! _root ) return(0);
   Fl_Tree_Item *item = _root;
@@ -864,12 +1221,18 @@
   return(item);
 }
 
-/// Returns the last visible item in the tree.
-/// \returns last visible item in the tree, or 0 if none.
+/// Returns the last open(), visible item in the tree.
+/// \deprecated in 1.3.3 ABI -- use last_visible_item() instead.
 ///
-/// \see first_visible(), last_visible()
+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() {
+Fl_Tree_Item* Fl_Tree::last_visible_item() {
   Fl_Tree_Item *item = last();
   while ( item ) {
     if ( item->visible() ) {
@@ -886,46 +1249,182 @@
 
 /// 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
   }
-  while ( (item = item->next()) )
-    if ( item->is_selected() )
-      return(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);
+  }
   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 @@
 ///       ..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,18 +1449,20 @@
 }
 #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.
 ///
 /// \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::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,11 +1480,13 @@
   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,65 +1496,67 @@
 /// \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.
 ///
 /// \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.
 ///
 /// \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,10 +1564,12 @@
   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 @@
 /// \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 @@
   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 @@
 ///     -    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 @@
   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 @@
   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,10 +1656,11 @@
   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,10 +1695,12 @@
   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 @@
 /// \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,17 +1723,19 @@
   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.
 ///
 /// \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,16 +1749,18 @@
 }
 
 /// 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.
 ///
 /// \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,10 +1779,12 @@
   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 @@
 /// \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,11 +1807,13 @@
   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,11 +1821,10 @@
 ///                 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()
   if ( ! item ) return(0);
@@ -1322,21 +1840,23 @@
   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.
 ///
 /// \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,11 +1892,13 @@
   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 @@
 ///            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 @@
 }
 
 /// 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 @@
   }
 }
 
-/// 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 @@
   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 @@
 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 @@
 void Fl_Tree::margintop(int val) {
   _prefs.margintop(val);
   redraw();
+  recalc_tree();
 }
 
 #if FLTK_ABI_VERSION >= 10301
@@ -1553,6 +2078,7 @@
 void Fl_Tree::marginbottom(int val) {
   _prefs.marginbottom(val);
   redraw();
+  recalc_tree();
 }
 #endif /*FLTK_ABI_VERSION*/
 
@@ -1569,6 +2095,7 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 }
 
 /// 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 @@
 }
 
 /// 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 @@
 }
 
 /// 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 @@
 }
 
 /// 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 @@
 }
 
 /// 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 @@
   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
+/// \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().
 ///
-/// 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 @@
   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 @@
   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 @@
   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 @@
   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 @@
 
 /// 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 @@
   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 @@
 /// \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 @@
   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 @@
 /// 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 @@
   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 @@
 }
 
 /// 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 @@
  * 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 @@
   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$".
 //
Index: branches/branch-1.3/FL/Fl_Tree_Item.H
===================================================================
--- branches/branch-1.3/FL/Fl_Tree_Item.H	(revision 10033)
+++ branches/branch-1.3/FL/Fl_Tree_Item.H	(revision 10034)
@@ -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 @@
   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 @@
   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 @@
   /// 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 @@
   /// 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 @@
   /// 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 @@
   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 @@
   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 @@
   }
   /// 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 @@
   /// 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 @@
   //////////////////
   // 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 @@
 #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.
Index: branches/branch-1.3/FL/Fl_Tree.H
===================================================================
--- branches/branch-1.3/FL/Fl_Tree.H	(revision 10033)
+++ branches/branch-1.3/FL/Fl_Tree.H	(revision 10034)
@@ -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().
+///     via Fl_Tree::item_draw_callback().<BR>
 ///
-/// \b SELECTION OF ITEMS
-///
+/// \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 @@
   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 @@
   int handle(int e);
   void draw();
   void show_self();
-  
+  void resize(int,int,int,int);
+
   ///////////////////////
   // root methods
   ///////////////////////
@@ -352,7 +377,7 @@
   // 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 @@
   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 @@
   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 @@
   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 @@
   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
Index: branches/branch-1.3/FL/Fl_Tree_Prefs.H
===================================================================
--- branches/branch-1.3/FL/Fl_Tree_Prefs.H	(revision 10033)
+++ branches/branch-1.3/FL/Fl_Tree_Prefs.H	(revision 10034)
@@ -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
Index: branches/branch-1.3/CHANGES
===================================================================
--- branches/branch-1.3/CHANGES	(revision 10033)
+++ branches/branch-1.3/CHANGES	(revision 10034)
@@ -29,7 +29,39 @@
 	- 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
 
 	- Removed unnecessary drawing calls (STR #2898)
Index: branches/branch-1.3/test/tree.fl
===================================================================
--- branches/branch-1.3/test/tree.fl	(revision 10033)
+++ branches/branch-1.3/test/tree.fl	(revision 10034)
@@ -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 <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/Yyy");
 tree->add("Descending/Ccc");
 
+// 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
-tree->sortorder(FL_TREE_SORT_NONE);
 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 @@
 } {
   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 @@
       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->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 @@
 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 @@
 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 @@
         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 @@
     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 @@
     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 @@
 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 @@
       }
       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 @@
 // 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 @@
 // 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 @@
     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 @@
         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 @@
 }
 
 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 @@
 }
 
 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();}
         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 @@
 }
 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 @@
         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 @@
 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 @@
         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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
         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 @@
 "   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 @@
   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 @@
 
 //Fl::scheme("gtk+");
 
+Fl_Tooltip::size(10);		// small font for tooltips
+
 window->resizable(tree);
 window->size_range(window->w(), window->h(), 0, 0);
 

Direct Link to Message ]
 
     
Previous Message ]Next Message ]
 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.