summaryrefslogtreecommitdiff
path: root/src/Fl_Tree_Item.cxx
diff options
context:
space:
mode:
authorGreg Ercolano <erco@seriss.com>2014-01-20 21:23:24 +0000
committerGreg Ercolano <erco@seriss.com>2014-01-20 21:23:24 +0000
commitabdc83470530c5fa8e15370a2032093cd91dace7 (patch)
treedea9946420c6788e8fde4bcabd839e599138666b /src/Fl_Tree_Item.cxx
parentaa71c2f6e1d7c78acc4eb7c6603761423d859390 (diff)
o Added draw_item_content() to Fl_Tree_Item,
a volatile method that can be overridden by subclasses to take drawing control of tree item's content. This replaces the old "item_draw_callback()" technique added a few months ago as an ABI feature; turned out the new technique is a better way to go. o The examples/tree-custom-draw-items.cxx demo adjusted accordingly. o Added missing docs for some methods that had none, including label_[xywh](). o Added related methods needed to implement this, including: Fl_Tree_Item_Array::replace() Fl_Tree_Item::replace() Fl_Tree::root(item) Fl_Tree::add() variations Fl_Tree_Item::drawbgcolor()/drawfgcolor() o Carefully worked the FLTK_ABI_VERSION macros so as to be ABI compatible with 1.3.0. o Verified 1.3.0 ABI compatibility with ABI Compliance Checker 1.99.8.5: http://ispras.linuxbase.org/index.php/ABI_compliance_checker git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10071 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/Fl_Tree_Item.cxx')
-rw-r--r--src/Fl_Tree_Item.cxx551
1 files changed, 403 insertions, 148 deletions
diff --git a/src/Fl_Tree_Item.cxx b/src/Fl_Tree_Item.cxx
index ca0fdfcb3..202ad09a4 100644
--- a/src/Fl_Tree_Item.cxx
+++ b/src/Fl_Tree_Item.cxx
@@ -36,7 +36,9 @@ static int event_inside(const int xywh[4]) {
/// Constructor.
/// 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.
+#if FLTK_ABI_VERSION >= 10303
+/// \deprecated in 1.3.3 ABI -- you must use Fl_Tree_Item(Fl_Tree*) for proper horizontal scrollbar behavior.
+#endif
///
Fl_Tree_Item::Fl_Tree_Item(const Fl_Tree_Prefs &prefs) {
_Init(prefs, 0);
@@ -91,6 +93,11 @@ void Fl_Tree_Item::_Init(const Fl_Tree_Prefs &prefs, Fl_Tree *tree) {
/// Constructor.
/// Makes a new instance of Fl_Tree_Item for \p 'tree'.
///
+/// This must be used instead of the older, deprecated Fl_Tree_Item(Fl_Tree_Prefs)
+/// constructor for proper horizontal scrollbar calculation.
+///
+/// \version 1.3.3 ABI feature
+///
Fl_Tree_Item::Fl_Tree_Item(Fl_Tree *tree) {
_Init(tree->_prefs, tree);
}
@@ -186,7 +193,7 @@ const char *Fl_Tree_Item::label() const {
return(_label);
}
-/// Return child item for the specified 'index'.
+/// Return const child item for the specified 'index'.
const Fl_Tree_Item *Fl_Tree_Item::child(int index) const {
return(_children[index]);
}
@@ -201,25 +208,51 @@ void Fl_Tree_Item::clear_children() {
/// that has the label \p 'name'.
///
/// \returns index of found item, or -1 if not found.
+/// \version 1.3.0 release
///
int Fl_Tree_Item::find_child(const char *name) {
if ( name ) {
- for ( int t=0; t<children(); t++ ) {
- if ( child(t)->label() ) {
- if ( strcmp(child(t)->label(), name) == 0 ) {
+ for ( int t=0; t<children(); t++ )
+ if ( child(t)->label() )
+ if ( strcmp(child(t)->label(), name) == 0 )
return(t);
- }
- }
- }
}
return(-1);
}
+/// Return the /immediate/ child of current item
+/// that has the label \p 'name'.
+///
+/// \returns const found item, or 0 if not found.
+/// \version 1.3.3
+///
+const Fl_Tree_Item* Fl_Tree_Item::find_child_item(const char *name) const {
+ if ( name )
+ for ( int t=0; t<children(); t++ )
+ if ( child(t)->label() )
+ if ( strcmp(child(t)->label(), name) == 0 )
+ return(child(t));
+ return(0);
+}
+
+/// Return the /immediate/ child of current item
+/// that has the label \p 'name'.
+///
+/// \returns found item, or 0 if not found.
+/// \version 1.3.3
+///
+Fl_Tree_Item* Fl_Tree_Item::find_child_item(const char *name) {
+ // "Effective C++, 3rd Ed", p.23. Sola fide, Amen.
+ return(const_cast<Fl_Tree_Item*>(
+ static_cast<const Fl_Tree_Item &>(*this).find_child_item(name)));
+}
+
/// 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
+/// \version 1.3.0 release
///
const Fl_Tree_Item *Fl_Tree_Item::find_child_item(char **arr) const {
for ( int t=0; t<children(); t++ ) {
@@ -241,9 +274,10 @@ const Fl_Tree_Item *Fl_Tree_Item::find_child_item(char **arr) const {
/// Only Fl_Tree should need this method. Use Fl_Tree::find_item() instead.
///
/// \returns item, or 0 if not found
+/// \version 1.3.0 release
///
Fl_Tree_Item *Fl_Tree_Item::find_child_item(char **arr) {
- // I evoke "Effective C++, 3rd Ed", p.23. Sola fide, Amen.
+ // "Effective C++, 3rd Ed", p.23. Sola fide, Amen.
return(const_cast<Fl_Tree_Item*>(
static_cast<const Fl_Tree_Item &>(*this).find_child_item(arr)));
}
@@ -252,9 +286,10 @@ Fl_Tree_Item *Fl_Tree_Item::find_child_item(char **arr) {
/// Includes self in search.
/// Only Fl_Tree should need this method. Use Fl_Tree::find_item() instead.
///
-/// \returns item, or 0 if not found
+/// \returns const item, or 0 if not found
///
const Fl_Tree_Item *Fl_Tree_Item::find_item(char **names) const {
+ if ( ! *names ) return(0);
if ( label() && strcmp(label(), *names) == 0 ) { // match self?
++names; // skip self
if ( *names == 0 ) return(this); // end of names, found ourself
@@ -272,7 +307,7 @@ const Fl_Tree_Item *Fl_Tree_Item::find_item(char **names) const {
/// \returns item, or 0 if not found
///
Fl_Tree_Item *Fl_Tree_Item::find_item(char **names) {
- // I evoke "Effective C++, 3rd Ed", p.23. Sola fide, Amen.
+ // "Effective C++, 3rd Ed", p.23. Sola fide, Amen.
return(const_cast<Fl_Tree_Item*>(
static_cast<const Fl_Tree_Item &>(*this).find_item(names)));
}
@@ -283,11 +318,9 @@ Fl_Tree_Item *Fl_Tree_Item::find_item(char **names) {
/// \returns the index, or -1 if not found.
///
int Fl_Tree_Item::find_child(Fl_Tree_Item *item) {
- for ( int t=0; t<children(); t++ ) {
- if ( item == child(t) ) {
+ for ( int t=0; t<children(); t++ )
+ if ( item == child(t) )
return(t);
- }
- }
return(-1);
}
@@ -295,15 +328,33 @@ int Fl_Tree_Item::find_child(Fl_Tree_Item *item) {
/// 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().
+/// \returns the item added
+/// \version 1.3.0 release
+///
+Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs,
+ const char *new_label) {
+ return(add(prefs, new_label, (Fl_Tree_Item*)0));
+}
+
+/// Add \p 'item' as immediate child with \p 'new_label'
+/// and defaults from \p 'prefs'.
+/// If \p 'item' is NULL, a new item is created.
+/// An internally managed copy is made of the label string.
+/// Adds the item based on the value of prefs.sortorder().
+/// \returns the item added
+/// \version 1.3.3
///
-Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs, const char *new_label) {
+Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs,
+ const char *new_label,
+ Fl_Tree_Item *item) {
#if FLTK_ABI_VERSION >= 10303
- Fl_Tree_Item *item = new Fl_Tree_Item(_tree);
+ if ( !item )
+ { item = new Fl_Tree_Item(_tree); item->label(new_label); }
#else
- Fl_Tree_Item *item = new Fl_Tree_Item(prefs);
+ if ( !item )
+ { item = new Fl_Tree_Item(prefs); item->label(new_label); }
#endif
recalc_tree(); // may change tree geometry
- item->label(new_label);
item->_parent = this;
switch ( prefs.sortorder() ) {
case FL_TREE_SORT_NONE: {
@@ -340,21 +391,49 @@ Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs, const char *new_labe
/// Should be used only by Fl_Tree's internals.
/// Adds the item based on the value of prefs.sortorder().
/// \returns the item added.
+/// \version 1.3.0 release
///
Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs, char **arr) {
- int t = (*arr && *(arr+1)) ? find_child(*arr) : -1;
- Fl_Tree_Item *item = 0;
- if ( t == -1 ) {
- item = (Fl_Tree_Item*)add(prefs, *arr);
- } else {
- item = (Fl_Tree_Item*)child(t);
- }
- recalc_tree(); // may change tree geometry
- if ( *(arr+1) ) { // descend?
- return(item->add(prefs, arr+1));
- } else {
- return(item); // end? done
+ return add(prefs, arr, 0);
+}
+
+/// Descend into path specified by \p 'arr' and add \p 'newitem' there.
+/// Should be used only by Fl_Tree's internals.
+/// If item is NULL, a new item is created.
+/// Adds the item based on the value of prefs.sortorder().
+/// \returns the item added.
+/// \version 1.3.3 ABI feature
+///
+Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs,
+ char **arr,
+ Fl_Tree_Item *newitem) {
+ if ( !*arr ) return 0;
+ // See if we can find an existing child with name requested.
+ Fl_Tree_Item *child = find_child_item(*arr);
+ if ( child ) { // Child found?
+ if ( *(arr+1) == 0 ) { // ..and at end of path?
+ if ( !newitem ) { // ..and no item specified?
+ return 0; // ..error: child exists already
+ } else {
+ // Child found, end of path, item specified
+ return child->add(prefs, newitem->label(), newitem);
+ }
+ }
+ // Child found: more path elements to go or item specified?
+ // Descend into child to handle add..
+ return child->add(prefs, arr+1, newitem); // recurse
}
+ // No child found, see if we reached end of path.
+ // If so, add as an immediate child, done
+ if ( *(arr+1) == 0 ) // end of path?
+ return add(prefs, *arr, newitem); // add as immediate child
+
+ // No child found, but more to path?
+ // If so, create new child to handle add()
+ Fl_Tree_Item *newchild;
+ return (newchild=add(prefs, *arr)) // create new immediate child
+ ? newchild->add(prefs,arr+1,newitem) // it worked? recurse to add
+ : 0; // failed? error
}
/// Insert a new item named \p 'new_label' into current item's
@@ -390,6 +469,64 @@ Fl_Tree_Item *Fl_Tree_Item::insert_above(const Fl_Tree_Prefs &prefs, const char
return(0);
}
+#if FLTK_ABI_VERSION >= 10303
+/// Return the parent tree's prefs.
+/// \returns a reference to the parent tree's Fl_Tree_Prefs
+/// \version 1.3.3 ABI feature
+///
+const Fl_Tree_Prefs& Fl_Tree_Item::prefs() const {
+ return(_tree->_prefs);
+}
+
+/// Replace the current item with a new item.
+///
+/// The current item is destroyed if successful.
+/// No checks are made to see if an item with the same name exists.
+///
+/// This method can be used to, for example, install 'custom' items
+/// into the tree derived from Fl_Tree_Item; see draw_item_content().
+///
+/// \param[in] newitem The new item to replace the current item
+/// \returns newitem on success, NULL if could not be replaced.
+/// \see Fl_Tree_Item::draw_item_content(), Fl_Tree::root(Fl_Tree_Item*)
+/// \version 1.3.3 ABI feature
+///
+Fl_Tree_Item *Fl_Tree_Item::replace(Fl_Tree_Item *newitem) {
+ Fl_Tree_Item *p = parent();
+ if ( !p ) { // no parent? then we're the tree's root..
+ _tree->root(newitem); // ..tell tree to replace root
+ return newitem;
+ }
+ // has parent? ask parent to replace us
+ return p->replace_child(this, newitem);
+}
+
+/// Replace existing child \p 'olditem' with \p 'newitem'.
+///
+/// The \p 'olditem' is destroyed if successful.
+/// Can be used to put custom items (derived from Fl_Tree_Item) into the tree.
+/// No checks are made to see if an item with the same name exists.
+///
+/// \param[in] olditem The item to be found and replaced
+/// \param[in] newitem The new item to take the place of \p 'olditem'
+/// \returns newitem on success and \p 'olditem' is destroyed.
+/// NULL on error if \p 'olditem' was not found
+/// as an immediate child.
+/// \see replace(), Fl_Tree_Item::draw()
+/// \version 1.3.3 ABI feature
+///
+Fl_Tree_Item *Fl_Tree_Item::replace_child(Fl_Tree_Item *olditem,
+ Fl_Tree_Item *newitem) {
+ int pos = find_child(olditem); // find our index for olditem
+ if ( pos == -1 ) return(NULL);
+ newitem->_parent = this;
+ // replace in array (handles stitching neighboring items)
+ _children.replace(pos, newitem);
+ recalc_tree(); // newitem may have changed tree geometry
+ return newitem;
+}
+#endif
+
/// Remove \p 'item' from the current item's children.
/// \returns 0 if removed, -1 if item not an immediate child.
///
@@ -406,7 +543,11 @@ int Fl_Tree_Item::remove_child(Fl_Tree_Item *item) {
}
/// Remove immediate child (and its children) by its label \p 'name'.
+/// If more than one item matches \p 'name', only the first
+/// matching item is removed.
+/// \param[in] name The label name of the immediate child to remove
/// \returns 0 if removed, -1 if not found.
+/// \version 1.3.3
///
int Fl_Tree_Item::remove_child(const char *name) {
for ( int t=0; t<children(); t++ ) {
@@ -425,6 +566,7 @@ int Fl_Tree_Item::remove_child(const char *name) {
/// 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.
+/// \param[in] ax,bx the index of the items to swap
///
void Fl_Tree_Item::swap_children(int ax, int bx) {
_children.swap(ax, bx);
@@ -435,6 +577,9 @@ void Fl_Tree_Item::swap_children(int ax, int bx) {
///
/// This method is SLOW because it involves linear lookups.<br>
/// For speed, use swap_children(int,int) instead.
+///
+/// \param[in] a,b The item ptrs of the two items to swap.
+/// Both must be immediate children of the current item.
/// \returns
/// - 0 : OK
/// - -1 : failed: item \p 'a' or \p 'b' is not our child.
@@ -451,6 +596,11 @@ int Fl_Tree_Item::swap_children(Fl_Tree_Item *a, Fl_Tree_Item *b) {
}
/// Internal: Horizontal connector line based on preference settings.
+/// \param[in] x1 The left hand X position of the horizontal connector
+/// \param[in] x2 The right hand X position of the horizontal connector
+/// \param[in] y The vertical position of the horizontal connector
+/// \param[in] prefs The Fl_Tree prefs
+///
void Fl_Tree_Item::draw_horizontal_connector(int x1, int x2, int y, const Fl_Tree_Prefs &prefs) {
fl_color(prefs.connectorcolor());
switch ( prefs.connectorstyle() ) {
@@ -472,6 +622,11 @@ void Fl_Tree_Item::draw_horizontal_connector(int x1, int x2, int y, const Fl_Tre
}
/// Internal: Vertical connector line based on preference settings.
+/// \param[in] x The x position of the vertical connector
+/// \param[in] y1 The top of the vertical connector
+/// \param[in] y2 The bottom of the vertical connector
+/// \param[in] prefs The Fl_Tree prefs
+///
void Fl_Tree_Item::draw_vertical_connector(int x, int y1, int y2, const Fl_Tree_Prefs &prefs) {
fl_color(prefs.connectorcolor());
switch ( prefs.connectorstyle() ) {
@@ -535,7 +690,7 @@ const Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs, int y
/// \param[in] yonly -- 0: check both event's X and Y values.
/// -- 1: only check event's Y value, don't care about X.
/// \returns pointer to clicked item, or NULL if none found
-/// \version 1.3.3 ABI
+/// \version 1.3.3 ABI feature
///
Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs, int yonly) {
// "Effective C++, 3rd Ed", p.23. Sola fide, Amen.
@@ -620,8 +775,14 @@ static void draw_item_focus(Fl_Boxtype B, Fl_Color fg, Fl_Color bg, int X, int Y
#endif
}
-/// Return the item's 'visible' height.
-/// Doesn't include linespacing(); prevents affecting e.g. height of widget().
+/// Return the item's 'visible' height. Takes into account the item's:
+/// - visibility (if !is_visible(), returns 0)
+/// - labelfont() height: if label() != NULL
+/// - widget() height: if widget() != NULL
+/// - openicon() height (if not NULL)
+/// - usericon() height (if not NULL)
+/// Does NOT include Fl_Tree::linespacing();
+/// \returns maximum pixel height
///
int Fl_Tree_Item::calc_item_height(const Fl_Tree_Prefs &prefs) const {
if ( ! is_visible() ) return(0);
@@ -645,26 +806,154 @@ int Fl_Tree_Item::calc_item_height(const Fl_Tree_Prefs &prefs) const {
}
#if FLTK_ABI_VERSION >= 10303
+// These methods held for 1.3.3 ABI: all need 'tree()' back-reference.
+
+/// Returns the recommended foreground color used for drawing this item.
+/// \see draw_item_content()
+/// \version 1.3.3 ABI ABI
+///
+Fl_Color Fl_Tree_Item::drawfgcolor() const {
+ return is_selected() ? fl_contrast(_labelfgcolor, tree()->selection_color())
+ : is_active() ? _labelfgcolor
+ : fl_inactive(_labelfgcolor);
+}
+
+/// Returns the recommended background color used for drawing this item.
+/// \see draw_item_content()
+/// \version 1.3.3 ABI
+///
+Fl_Color Fl_Tree_Item::drawbgcolor() const {
+ const Fl_Color unspecified = 0xffffffff;
+ return is_selected() ? is_active() ? tree()->selection_color()
+ : fl_inactive(tree()->selection_color())
+ : _labelbgcolor == unspecified ? tree()->color()
+ : _labelbgcolor;
+}
+
+/// Draw the item content
+///
+/// This method can be overridden to implement custom drawing
+/// by filling the label_[xywh]() area with content.
+///
+/// A minimal example of how to override draw_item_content()
+/// and draw just a normal item's background and label ourselves:
+///
+/// \code
+/// class MyTreeItem : public Fl_Tree_Item {
+/// public:
+/// MyTreeItem() { }
+/// ~MyTreeItem() { }
+/// // DRAW OUR CUSTOM CONTENT FOR THE ITEM
+/// int draw_item_content(int render) {
+/// // Our item's dimensions + text content
+/// int X=label_x(), Y=label_y(), W=label_w(), H=label_h();
+/// const char *text = label() ? label() : "";
+/// // Rendering? Do any drawing that's needed
+/// if ( render ) {
+/// // Draw bg -- a filled rectangle
+/// fl_color(drawbgcolor()); fl_rectf(X,Y,W,H);
+/// // Draw label
+/// fl_font(labelfont(), labelsize()); // use item's label font/size
+/// fl_color(drawfgcolor()); // use recommended fg color
+/// fl_draw(text, X,Y,W,H, FL_ALIGN_LEFT); // draw the item's label
+/// }
+/// // Rendered or not, we must calculate content's max X position
+/// int lw=0, lh=0;
+/// fl_measure(text, lw, lh); // get width of label text
+/// return X + lw; // return X + label width
+/// }
+/// };
+/// \endcode
+///
+/// You can draw anything you want inside draw_item_content()
+/// using any of the fl_draw.H functions, as long as it's
+/// within the label's xywh area.
+///
+/// To add instances of your custom item to the tree, you can use:
+///
+/// \code
+/// // Example #1: using add()
+/// MyTreeItem *bart = new MyTreeItem(..); // class derived from Fl_Tree_Item
+/// tree->add("/Simpsons/Bart", bart); // Add item as /Simpsons/Bart
+/// \endcode
+///
+/// ..or you can insert or replace existing items:
+///
+/// \code
+/// // Example #2: using replace()
+/// MyTreeItem *marge = new MyTreeItem(..); // class derived from Fl_Tree_Item
+/// item = tree->add("/Simpsons/Marge"); // create item
+/// item->replace(mi); // replace it with our own
+/// \endcode
+///
+/// \param[in] render Whether we should render content (1), or just tally
+/// the geometry (0). Fl_Tree may want only to find the widest
+/// item in the tree for scrollbar calculations.
+///
+/// \returns the right-most X coordinate, or 'xmax' of content we drew,
+/// i.e. the "scrollable" content.
+/// The tree uses the largest xmax to determine the maximum
+/// width of the tree's content (needed for e.g. computing the
+/// horizontal scrollbar's size).
+/// \version 1.3.3 ABI feature
+///
+int Fl_Tree_Item::draw_item_content(int render) {
+ Fl_Color fg = drawfgcolor();
+ Fl_Color bg = drawbgcolor();
+ const Fl_Tree_Prefs &prefs = tree()->prefs();
+ int xmax = label_x();
+ // Background for this item, 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(),
+ label_x(), label_y(), label_w(), label_h(), bg);
+ } else { // Not Selected? use plain filled rectangle
+ fl_color(bg);
+ fl_rectf(label_x(), label_y(), label_w(), label_h());
+ }
+ if ( widget() ) widget()->damage(FL_DAMAGE_ALL); // if there's a child widget, we just damaged it
+ }
+ // 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 lx = label_x()+(_label ? prefs.labelmarginleft() : 0);
+ int ly = label_y()+(label_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, lx, ly);
+ xmax = lx + lw; // update max width of drawn item
+ }
+ return xmax;
+}
+
/// 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] 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 for 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
+/// 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 w/out drawing.
+/// 1: render item as well as size calc
+///
+/// \version 1.3.3 ABI feature: modified parameters
///
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 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
@@ -697,23 +986,22 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Tree_Item *itemfocus,
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;
+ int uicon_x = X+(icon_w/2-1+conn_w) + ( (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);
+ // Label xywh
+ _label_xywh[0] = uicon_x + uicon_w + prefs.labelmarginleft();
+ _label_xywh[1] = Y;
+ _label_xywh[2] = tree()->_tix + tree()->_tiw - _label_xywh[0];
+ _label_xywh[3] = H;
// Begin calc of this item's max width..
// It might not even be visible, so start at zero.
//
- int ixmax = 0;
+ int xmax = 0;
// Recalc widget position
// Do this whether clipped or not, so that when scrolled,
@@ -721,8 +1009,8 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Tree_Item *itemfocus,
// (so that they don't get mouse events, etc)
//
if ( widget() ) {
- int wx = label_x;
- int wy = bg_y;
+ int wx = uicon_x + uicon_w + (_label ? prefs.labelmarginleft() : 0);
+ int wy = label_y();
int ww = widget()->w(); // use widget's width
int wh = (prefs.item_draw_mode() & FL_TREE_ITEM_HEIGHT_FROM_WIDGET)
? widget()->h() : H;
@@ -742,19 +1030,14 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Tree_Item *itemfocus,
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;
+ Fl_Color fg = drawfgcolor();
+ Fl_Color bg = drawbgcolor();
// 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?
+ 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
@@ -779,17 +1062,6 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Tree_Item *itemfocus,
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
@@ -800,44 +1072,31 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Tree_Item *itemfocus,
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
- }
+ // Draw item's content
+ xmax = draw_item_content(render);
} // end non-child damage
// Draw child FLTK widget?
if ( widget() ) {
if (render)
- _tree->draw_child(*widget()); // let group handle drawing child
+ 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
+ tree()->draw_outside_label(*widget());// label too
+ xmax = 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 &&
+ 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);
+ draw_item_focus(FL_NO_BOX,fg,bg,label_x()+1,label_y()+1,label_w()-1,label_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;
+ if ( xmax > tree_item_xmax )
+ tree_item_xmax = xmax;
// 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,
@@ -866,13 +1125,16 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Tree_Item *itemfocus,
/// 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,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?
///
+/// \version 1.3.0 release, removed 1.3.3 ABI
+///
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) {
@@ -961,13 +1223,14 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Widget *tree,
char clipped = ((Y+H) < tree_top) || (Y>tree_bot) ? 1 : 0;
char drawthis = ( is_root() && prefs.showroot() == 0 ) ? 0 : 1;
if ( !clipped ) {
+ const Fl_Color unspecified = 0xffffffff;
Fl_Color fg = is_selected() ? fl_contrast(_labelfgcolor, tree->selection_color())
- : is_active() ? _labelfgcolor
+ : 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;
+ : _labelbgcolor == unspecified ? tree->color()
+ : _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.
@@ -998,51 +1261,40 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Widget *tree,
prefs.openicon()->draw(icon_x,icon_y);
}
}
- // Draw the item
-#if FLTK_ABI_VERSION >= 10303
- if ( !widget() && prefs.item_draw_callback() ) {
- // Draw item using user supplied custom item draw callback
- prefs.do_item_draw_callback(this);
- }
- else
-#endif
- {
- // Background for this item
- // Draw bg only if different from tree's bg
- if ( 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 ( usericon() ) {
- // Item has user icon? Use it
- int uicon_y = item_y_center - (usericon()->h() >> 1);
- usericon()->draw(uicon_x,uicon_y);
- } else if ( 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 background for the item.. only if different from tree's bg color
+ if ( 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);
}
- // Draw label
+ if ( widget() ) widget()->damage(FL_DAMAGE_ALL); // if there's a child widget, we just damaged it
+ }
+ // Draw user icon (if any)
+ if ( usericon() ) {
+ // Item has user icon? Use it
+ int uicon_y = item_y_center - (usericon()->h() >> 1);
+ usericon()->draw(uicon_x,uicon_y);
+ } else if ( 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 FLTK_ABI_VERSION >= 10301
- if ( _label &&
- ( !widget() ||
- (prefs.item_draw_mode() & FL_TREE_ITEM_DRAW_LABEL_AND_WIDGET) ) )
+ if ( _label &&
+ ( !widget() ||
+ (prefs.item_draw_mode() & FL_TREE_ITEM_DRAW_LABEL_AND_WIDGET) ) )
#else /*FLTK_ABI_VERSION*/
- if ( _label && !widget() ) // back compat: don't draw label if widget() present
+ if ( _label && !widget() ) // back compat: don't draw label if widget() present
#endif /*FLTK_ABI_VERSION*/
- {
- fl_color(fg);
- fl_font(_labelfont, _labelsize);
- int label_y = Y+(H/2)+(_labelsize/2)-fl_descent()/2;
- fl_draw(_label, label_x, label_y);
- }
- } // end non-custom draw
+ {
+ fl_color(fg);
+ fl_font(_labelfont, _labelsize);
+ int label_y = Y+(H/2)+(_labelsize/2)-fl_descent()/2;
+ fl_draw(_label, label_x, label_y);
+ }
} // end non-child damage
// Draw child FLTK widget?
if ( widget() ) {
@@ -1292,7 +1544,8 @@ Fl_Tree_Item *Fl_Tree_Item::prev_sibling() {
/// 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.
+/// Call this whenever items in the array are added/removed/moved/swapped/etc.
+/// \param[in] index Our index# in the parent
///
void Fl_Tree_Item::update_prev_next(int index) {
#if FLTK_ABI_VERSION >= 10301
@@ -1323,6 +1576,7 @@ void Fl_Tree_Item::update_prev_next(int index) {
///
/// \returns the next open() visible() item below us,
/// or 0 if there's no more items.
+/// \version 1.3.3
///
Fl_Tree_Item *Fl_Tree_Item::next_visible(Fl_Tree_Prefs &prefs) {
Fl_Tree_Item *item = this;
@@ -1335,7 +1589,7 @@ Fl_Tree_Item *Fl_Tree_Item::next_visible(Fl_Tree_Prefs &prefs) {
}
/// Same as next_visible().
-/// \deprecated in 1.3.3 ABI for confusing name, use next_visible()
+/// \deprecated in 1.3.3 for confusing name, use next_visible() instead
Fl_Tree_Item *Fl_Tree_Item::next_displayed(Fl_Tree_Prefs &prefs) {
return next_visible(prefs);
}
@@ -1370,7 +1624,7 @@ Fl_Tree_Item *Fl_Tree_Item::prev_visible(Fl_Tree_Prefs &prefs) {
}
/// Same as prev_visible().
-/// \deprecated in 1.3.3 ABI for confusing name, use prev_visible()
+/// \deprecated in 1.3.3 for confusing name, use prev_visible()
///
Fl_Tree_Item *Fl_Tree_Item::prev_displayed(Fl_Tree_Prefs &prefs) {
return prev_visible(prefs);
@@ -1391,6 +1645,7 @@ int Fl_Tree_Item::visible_r() const {
/// 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.
+/// \version 1.3.3 ABI
///
void Fl_Tree_Item::recalc_tree() {
#if FLTK_ABI_VERSION >= 10303