From abdc83470530c5fa8e15370a2032093cd91dace7 Mon Sep 17 00:00:00 2001 From: Greg Ercolano Date: Mon, 20 Jan 2014 21:23:24 +0000 Subject: 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 --- src/Fl_Tree_Item.cxx | 551 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 403 insertions(+), 148 deletions(-) (limited to 'src/Fl_Tree_Item.cxx') 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; tlabel() ) { - if ( strcmp(child(t)->label(), name) == 0 ) { + for ( int t=0; tlabel() ) + 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; tlabel() ) + 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( + static_cast(*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( static_cast(*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( static_cast(*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= 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 /// This method is FAST, and does not involve lookups.
/// 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.
/// 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 -- cgit v1.2.3