diff options
| author | Greg Ercolano <erco@seriss.com> | 2013-12-15 18:59:02 +0000 |
|---|---|---|
| committer | Greg Ercolano <erco@seriss.com> | 2013-12-15 18:59:02 +0000 |
| commit | d36882e67e2276a44336a63e498c46a73d21fcb6 (patch) | |
| tree | 519d7c91d077dce9dd1b21e20a7354a2a09f9658 /src/Fl_Tree_Item.cxx | |
| parent | 6bf1ddf2b1fcc62fa52007e477a848fc2518b4ba (diff) | |
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
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10034 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/Fl_Tree_Item.cxx')
| -rw-r--r-- | src/Fl_Tree_Item.cxx | 462 |
1 files changed, 377 insertions, 85 deletions
diff --git a/src/Fl_Tree_Item.cxx b/src/Fl_Tree_Item.cxx index 2bbbb107c..9c9c24678 100644 --- a/src/Fl_Tree_Item.cxx +++ b/src/Fl_Tree_Item.cxx @@ -35,9 +35,20 @@ static int event_inside(const int xywh[4]) { } /// Constructor. -/// Makes a new instance of Fl_Tree_Item using defaults from 'prefs'. +/// Makes a new instance of Fl_Tree_Item using defaults from \p 'prefs'. +/// \deprecated in 1.3.3 ABI -- use Fl_Tree_Item(Fl_Tree*) instead. /// Fl_Tree_Item::Fl_Tree_Item(const Fl_Tree_Prefs &prefs) { + _Init(prefs, 0); +} + +// Initialize the tree item +// Used by constructors +// +void Fl_Tree_Item::_Init(const Fl_Tree_Prefs &prefs, Fl_Tree *tree) { +#if FLTK_ABI_VERSION >= 10303 + _tree = tree; +#endif _label = 0; _labelfont = prefs.labelfont(); _labelsize = prefs.labelsize(); @@ -76,6 +87,15 @@ Fl_Tree_Item::Fl_Tree_Item(const Fl_Tree_Prefs &prefs) { #endif /*FLTK_ABI_VERSION*/ } +#if FLTK_ABI_VERSION >= 10303 +/// Constructor. +/// Makes a new instance of Fl_Tree_Item for \p 'tree'. +/// +Fl_Tree_Item::Fl_Tree_Item(Fl_Tree *tree) { + _Init(tree->_prefs, tree); +} +#endif + // DTOR Fl_Tree_Item::~Fl_Tree_Item() { if ( _label ) { @@ -89,6 +109,9 @@ Fl_Tree_Item::~Fl_Tree_Item() { /// Copy constructor. Fl_Tree_Item::Fl_Tree_Item(const Fl_Tree_Item *o) { +#if FLTK_ABI_VERSION >= 10303 + _tree = o->_tree; +#endif _label = o->label() ? strdup(o->label()) : 0; _labelfont = o->labelfont(); _labelsize = o->labelsize(); @@ -149,10 +172,13 @@ void Fl_Tree_Item::show_self(const char *indent) const { fflush(stdout); } -/// Set the label. Makes a copy of the name. +/// Set the label to \p 'name'. +/// Makes and manages an internal copy of \p 'name'. +/// void Fl_Tree_Item::label(const char *name) { if ( _label ) { free((void*)_label); _label = 0; } _label = name ? strdup(name) : 0; + recalc_tree(); // may change label geometry } /// Return the label. @@ -168,9 +194,11 @@ const Fl_Tree_Item *Fl_Tree_Item::child(int index) const { /// Clear all the children for this item. void Fl_Tree_Item::clear_children() { _children.clear(); + recalc_tree(); // may change tree geometry } -/// Return the index of the immediate child of this item that has the label 'name'. +/// Return the index of the immediate child of this item +/// that has the label \p 'name'. /// /// \returns index of found item, or -1 if not found. /// @@ -187,7 +215,8 @@ int Fl_Tree_Item::find_child(const char *name) { return(-1); } -/// Find child item by descending array of names. Does not include self in search. +/// Find child item by descending array \p 'arr' of names. +/// Does not include self in search. /// Only Fl_Tree should need this method. /// /// \returns item, or 0 if not found @@ -207,7 +236,8 @@ const Fl_Tree_Item *Fl_Tree_Item::find_child_item(char **arr) const { return(0); } -/// Find child item by descending array of names. Does not include self in search. +/// Find child item by descending array \p 'arr' of names. +/// Does not include self in search. /// Only Fl_Tree should need this method. Use Fl_Tree::find_item() instead. /// /// \returns item, or 0 if not found @@ -227,7 +257,8 @@ Fl_Tree_Item *Fl_Tree_Item::find_child_item(char **arr) { return(0); } -/// Find item by descending array of \p names. Includes self in search. +/// Find item by descending array of \p 'names'. +/// Includes self in search. /// Only Fl_Tree should need this method. Use Fl_Tree::find_item() instead. /// /// \returns item, or 0 if not found @@ -244,7 +275,8 @@ const Fl_Tree_Item *Fl_Tree_Item::find_item(char **names) const { return(0); } -/// Find item by descending array of \p names. Includes self in search. +/// Find item by descending array of \p 'names'. +/// Includes self in search. /// Only Fl_Tree should need this method. /// /// \returns item, or 0 if not found @@ -261,7 +293,7 @@ Fl_Tree_Item *Fl_Tree_Item::find_item(char **names) { return(0); } -/// Find the index number for the specified 'item' +/// Find the index number for the specified \p 'item' /// in the current item's list of children. /// /// \returns the index, or -1 if not found. @@ -275,12 +307,18 @@ int Fl_Tree_Item::find_child(Fl_Tree_Item *item) { return(-1); } -/// Add a new child to this item with the name 'new_label', with defaults from 'prefs'. +/// Add a new child to this item with the name \p 'new_label' +/// and defaults from \p 'prefs'. /// An internally managed copy is made of the label string. /// Adds the item based on the value of prefs.sortorder(). /// Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs, const char *new_label) { +#if FLTK_ABI_VERSION >= 10303 + Fl_Tree_Item *item = new Fl_Tree_Item(_tree); +#else Fl_Tree_Item *item = new Fl_Tree_Item(prefs); +#endif + recalc_tree(); // may change tree geometry item->label(new_label); item->_parent = this; switch ( prefs.sortorder() ) { @@ -314,7 +352,7 @@ Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs, const char *new_labe return(item); } -/// Descend into the path specified by \p arr, and add a new child there. +/// Descend into the path specified by \p 'arr', and add a new child there. /// Should be used only by Fl_Tree's internals. /// Adds the item based on the value of prefs.sortorder(). /// \returns the item added. @@ -327,6 +365,7 @@ Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs, char **arr) { } else { item = (Fl_Tree_Item*)child(t); } + recalc_tree(); // may change tree geometry if ( *(arr+1) ) { // descend? return(item->add(prefs, arr+1)); } else { @@ -334,18 +373,24 @@ Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs, char **arr) { } } -/// Insert a new item into current item's children at a specified position. +/// Insert a new item named \p 'new_label' into current item's +/// children at a specified position \p 'pos'. /// \returns the new item inserted. /// Fl_Tree_Item *Fl_Tree_Item::insert(const Fl_Tree_Prefs &prefs, const char *new_label, int pos) { +#if FLTK_ABI_VERSION >= 10303 + Fl_Tree_Item *item = new Fl_Tree_Item(_tree); +#else Fl_Tree_Item *item = new Fl_Tree_Item(prefs); +#endif item->label(new_label); item->_parent = this; _children.insert(pos, item); + recalc_tree(); // may change tree geometry return(item); } -/// Insert a new item above this item. +/// Insert a new item named \p 'new_label' above this item. /// \returns the new item inserted, or 0 if an error occurred. /// Fl_Tree_Item *Fl_Tree_Item::insert_above(const Fl_Tree_Prefs &prefs, const char *new_label) { @@ -361,21 +406,22 @@ Fl_Tree_Item *Fl_Tree_Item::insert_above(const Fl_Tree_Prefs &prefs, const char return(0); } -/// Remove child by item. -/// \returns 0 if removed, -1 if item not an immediate child. +/// Remove \p 'item' from the current item's children. +/// \returns 0 if removed, -1 if item not an immediate child. /// int Fl_Tree_Item::remove_child(Fl_Tree_Item *item) { for ( int t=0; t<children(); t++ ) { if ( child(t) == item ) { item->clear_children(); _children.remove(t); + recalc_tree(); // may change tree geometry return(0); } } return(-1); } -/// Remove immediate child (and its children) by its label 'name'. +/// Remove immediate child (and its children) by its label \p 'name'. /// \returns 0 if removed, -1 if not found. /// int Fl_Tree_Item::remove_child(const char *name) { @@ -383,6 +429,7 @@ int Fl_Tree_Item::remove_child(const char *name) { if ( child(t)->label() ) { if ( strcmp(child(t)->label(), name) == 0 ) { _children.remove(t); + recalc_tree(); // may change tree geometry return(0); } } @@ -390,30 +437,23 @@ int Fl_Tree_Item::remove_child(const char *name) { return(-1); } -/// Swap two of our children, given two child index values. -/// Use this eg. for sorting. -/// -/// This method is FAST, and does not involve lookups. -/// +/// Swap two of our children, given two child index values \p 'ax' and \p 'bx'. +/// Use e.g. for sorting.<br> +/// This method is FAST, and does not involve lookups.<br> /// No range checking is done on either index value. /// -/// \returns -/// - 0 : OK -/// - -1 : failed: 'a' or 'b' is not our immediate child -/// void Fl_Tree_Item::swap_children(int ax, int bx) { _children.swap(ax, bx); } -/// Swap two of our children, given item pointers. -/// Use this eg. for sorting. +/// Swap two of our immediate children, given item pointers. +/// Use e.g. for sorting. /// -/// This method is SLOW because it involves linear lookups. +/// This method is SLOW because it involves linear lookups.<br> /// For speed, use swap_children(int,int) instead. -/// /// \returns /// - 0 : OK -/// - -1 : failed: 'a' or 'b' is not our immediate child +/// - -1 : failed: item \p 'a' or \p 'b' is not our child. /// int Fl_Tree_Item::swap_children(Fl_Tree_Item *a, Fl_Tree_Item *b) { int ax = -1, bx = -1; @@ -470,28 +510,31 @@ void Fl_Tree_Item::draw_vertical_connector(int x, int y1, int y2, const Fl_Tree_ } } -/// Find the item that the last event was over. -/// -/// Returns the item if it is visible, and mouse is over it. -/// Works even if widget deactivated. -/// Use event_on_collapse_icon() to determine if collapse button was pressed. -/// -/// \returns const visible item under the event if found, or 0 if none. -/// -const Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs) const { +// Internal +// Find the item that the last event was over. +// If \p 'yonly' is 1, only check event's y value, don't care about x. +// +const Fl_Tree_Item *Fl_Tree_Item::find_clicked_(const Fl_Tree_Prefs &prefs, int yonly) const { if ( ! is_visible() ) return(0); if ( is_root() && !prefs.showroot() ) { // skip event check if we're root but root not being shown } else { // See if event is over us - if ( event_inside(_xywh) ) { // event within this item? - return(this); // found + if ( yonly ) { + if ( Fl::event_y() >= _xywh[1] && + Fl::event_y() <= (_xywh[1]+_xywh[3]) ) { + return(this); + } + } else { + if ( event_inside(_xywh) ) { // event within this item? + return(this); // found + } } } if ( is_open() ) { // open? check children of this item for ( int t=0; t<children(); t++ ) { const Fl_Tree_Item *item; - if ( ( item = _children[t]->find_clicked(prefs) ) != NULL) { // check child and its descendents + if ( (item = _children[t]->find_clicked(prefs, yonly)) != NULL) { // check child and its descendents return(item); // found? } } @@ -499,34 +542,24 @@ const Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs) const return(0); } -/// Non-const version of the above. /// Find the item that the last event was over. +/// There is both a const and non-const version of this method. /// -/// Returns the item if it is visible, and mouse is over it. -/// Works even if widget deactivated. -/// Use event_on_collapse_icon() to determine if collapse button was pressed. +/// Returns the item if it is visible, and mouse is over it. +/// Works even if widget deactivated. +/// Use event_on_collapse_icon() to determine if collapse button was pressed. /// -/// \returns the visible item under the event if found, or 0 if none. +/// If \a yonly is set, only the mouse Y position is checked. /// -Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs) { - if ( ! is_visible() ) return(0); - if ( is_root() && !prefs.showroot() ) { - // skip event check if we're root but root not being shown - } else { - // See if event is over us - if ( event_inside(_xywh) ) { // event within this item? - return(this); // found - } - } - if ( is_open() ) { // open? check children of this item - for ( int t=0; t<children(); t++ ) { - Fl_Tree_Item *item; - if ( ( item = _children[t]->find_clicked(prefs) ) != NULL ) { // check child and its descendents - return(item); // found? - } - } - } - return(0); +/// \returns const visible item under the event if found, or 0 if none. +/// +const Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs, int yonly) const { + return(find_clicked_(prefs, yonly)); +} + +/// A const version of Fl_Tree_Item::find_clicked() +Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs, int yonly) { + return((Fl_Tree_Item*)find_clicked_(prefs, yonly)); } static void draw_item_focus(Fl_Boxtype B, Fl_Color fg, Fl_Color bg, int X, int Y, int W, int H) { @@ -570,7 +603,7 @@ static void draw_item_focus(Fl_Boxtype B, Fl_Color fg, Fl_Color bg, int X, int Y } /// Return the item's 'visible' height. -/// Doesn't include linespacing(); prevents affecting eg. height of widget(). +/// Doesn't include linespacing(); prevents affecting e.g. height of widget(). /// int Fl_Tree_Item::calc_item_height(const Fl_Tree_Prefs &prefs) const { if ( ! is_visible() ) return(0); @@ -593,7 +626,235 @@ int Fl_Tree_Item::calc_item_height(const Fl_Tree_Prefs &prefs) const { return(H); } +#if FLTK_ABI_VERSION >= 10303 +/// Draw this item and its children. +/// +/// \param[in] X Horizontal position for item being drawn +/// \param[in,out] Y Vertical position for item being drawn, returns new position for next item +/// \param[in] W Recommended width of item +/// \param[in] itemfocus The tree's current focus item (if any) +/// \param[in,out] tree_item_xmax The tree's running xmax (right-most edge so far). +/// Mainly used by parent tree when render==0 to calculate tree's max width. +/// \param[in] lastchild Is this item the last child in a subtree? +/// \param[in] render Whether or not to render the item: +/// - 0 -- no rendering, just calculate size. +/// (used to calculate size of tree without doing drawing) +/// - 1 -- render the item as well as doing size calculations +/// +void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Tree_Item *itemfocus, + int &tree_item_xmax, int lastchild, int render) { + Fl_Tree_Prefs &prefs = _tree->_prefs; + if ( !is_visible() ) return; + int tree_top = _tree->_tiy; + int tree_bot = tree_top + _tree->_tih; + int H = calc_item_height(prefs); // height of item + int H2 = H + prefs.linespacing(); // height of item with line spacing + + // Update the xywh of this item + _xywh[0] = X; + _xywh[1] = Y; + _xywh[2] = W; + _xywh[3] = H; + + // Determine collapse icon's xywh + // Note: calculate collapse icon's xywh for possible mouse click detection. + // We don't care about items clipped off the viewport; they won't get mouse events. + // + int item_y_center = Y+(H/2); + _collapse_xywh[2] = prefs.openicon()->w(); + int &icon_w = _collapse_xywh[2]; + _collapse_xywh[0] = X + (icon_w + prefs.connectorwidth())/2 - 3; + int &icon_x = _collapse_xywh[0]; + _collapse_xywh[1] = item_y_center - (prefs.openicon()->h()/2); + int &icon_y = _collapse_xywh[1]; + _collapse_xywh[3] = prefs.openicon()->h(); + + // Horizontal connector values + // Must calculate these even if(clipped) because 'draw children' code (below) + // needs hconn_x_center value. (Otherwise, these calculations could be 'clipped') + // + int hconn_x = X+icon_w/2-1; + int hconn_x2 = hconn_x + prefs.connectorwidth(); + int hconn_x_center = X + icon_w + ((hconn_x2 - (X + icon_w)) / 2); + int cw1 = icon_w+prefs.connectorwidth()/2, cw2 = prefs.connectorwidth(); + int conn_w = cw1>cw2 ? cw1 : cw2; + + // Background xywh + int &bg_x = _label_xywh[0] = X+(icon_w/2-1+conn_w); + int &bg_y = _label_xywh[1] = Y; + int &bg_w = _label_xywh[2] = _tree->_tix + _tree->_tiw - bg_x; + int &bg_h = _label_xywh[3] = H; + + // Usericon position + int uicon_x = bg_x + ( (usericon() || prefs.usericon()) ? prefs.usericonmarginleft() : 0); + int uicon_w = usericon() ? usericon()->w() : prefs.usericon() ? prefs.usericon()->w() : 0; + + // Label position + int label_x = uicon_x + uicon_w + (_label ? prefs.labelmarginleft() : 0); + + // Begin calc of this item's max width.. + // It might not even be visible, so start at zero. + // + int ixmax = 0; + + // Recalc widget position + // Do this whether clipped or not, so that when scrolled, + // the widgets move to appropriate 'offscreen' positions + // (so that they don't get mouse events, etc) + // + if ( widget() ) { + int wx = label_x; + int wy = bg_y; + int ww = widget()->w(); // use widget's width + int wh = (prefs.item_draw_mode() & FL_TREE_ITEM_HEIGHT_FROM_WIDGET) + ? widget()->h() : H; + if ( _label && + (prefs.item_draw_mode() & FL_TREE_ITEM_DRAW_LABEL_AND_WIDGET) ) { + fl_font(_labelfont, _labelsize); // fldescent() needs this + int lw=0, lh=0; + fl_measure(_label,lw,lh); // get box around text (including white space) + wx += (lw + prefs.widgetmarginleft()); + } + if ( widget()->x() != wx || widget()->y() != wy || + widget()->w() != ww || widget()->h() != wh ) { + widget()->resize(wx,wy,ww,wh); // we'll handle redraw below + } + } + char clipped = ((Y+H) < tree_top) || (Y>tree_bot) ? 1 : 0; + if (!render) clipped = 0; // NOT rendering? Then don't clip, so we calc unclipped items + char drawthis = ( is_root() && prefs.showroot() == 0 ) ? 0 : 1; + if ( !clipped ) { + Fl_Color fg = is_selected() ? fl_contrast(_labelfgcolor, _tree->selection_color()) + : is_active() ? _labelfgcolor + : fl_inactive(_labelfgcolor); + Fl_Color bg = is_selected() ? is_active() ? _tree->selection_color() + : fl_inactive(_tree->selection_color()) + : _labelbgcolor == 0xffffffff ? _tree->color() // transparent bg? + : _labelbgcolor; + // See if we should draw this item + // If this item is root, and showroot() is disabled, don't draw. + // 'clipped' is an optimization to prevent drawing anything offscreen. + // + if ( drawthis ) { // draw this item at all? + if ( (_tree->damage() & ~FL_DAMAGE_CHILD) || !render ) { // non-child damage? + // Draw connectors + if ( render && prefs.connectorstyle() != FL_TREE_CONNECTOR_NONE ) { + // Horiz connector between center of icon and text + // if this is root, the connector should not dangle in thin air on the left + if (is_root()) draw_horizontal_connector(hconn_x_center, hconn_x2, item_y_center, prefs); + else draw_horizontal_connector(hconn_x, hconn_x2, item_y_center, prefs); + // Small vertical line down to children + if ( has_children() && is_open() ) + draw_vertical_connector(hconn_x_center, item_y_center, Y+H2, prefs); + // Connectors for last child + if ( !is_root() ) { + if ( lastchild ) draw_vertical_connector(hconn_x, Y, item_y_center, prefs); + else draw_vertical_connector(hconn_x, Y, Y+H2, prefs); + } + } + // Draw collapse icon + if ( render && has_children() && prefs.showcollapse() ) { + // Draw icon image + if ( is_open() ) { + prefs.closeicon()->draw(icon_x,icon_y); + } else { + prefs.openicon()->draw(icon_x,icon_y); + } + } + // Background for this item + // Draw bg only if different from tree's bg + if ( render && (bg != _tree->color() || is_selected()) ) { + if ( is_selected() ) { // Selected? Use selectbox() style + fl_draw_box(prefs.selectbox(),bg_x,bg_y,bg_w,bg_h,bg); + } else { // Not Selected? use plain filled rectangle + fl_color(bg); + fl_rectf(bg_x,bg_y,bg_w,bg_h); + } + if ( widget() ) widget()->damage(FL_DAMAGE_ALL); // if there's a child widget, we just damaged it + } + // Draw user icon (if any) + if ( render && usericon() ) { + // Item has user icon? Use it + int uicon_y = item_y_center - (usericon()->h() >> 1); + usericon()->draw(uicon_x,uicon_y); + } else if ( render && prefs.usericon() ) { + // Prefs has user icon? Use it + int uicon_y = item_y_center - (prefs.usericon()->h() >> 1); + prefs.usericon()->draw(uicon_x,uicon_y); + } + // Draw label + if ( _label && + ( !widget() || + (prefs.item_draw_mode() & FL_TREE_ITEM_DRAW_LABEL_AND_WIDGET) ) ) { + if ( render ) { + fl_color(fg); + fl_font(_labelfont, _labelsize); + } + int label_y = Y+(H/2)+(_labelsize/2)-fl_descent()/2; + + int lw=0, lh=0; + fl_measure(_label, lw, lh); // get box around text (including white space) + if ( render ) fl_draw(_label, label_x, label_y); + ixmax = label_x + lw; // update max width of drawn item + } + } // end non-child damage + // Draw child FLTK widget? + if ( widget() ) { + if (render) + _tree->draw_child(*widget()); // let group handle drawing child + if ( widget()->label() && render ) + _tree->draw_outside_label(*widget()); // label too + ixmax = widget()->x() + widget()->w(); // update max width of widget + } + // Draw focus box around item's bg last + if ( render && + this == itemfocus && + Fl::visible_focus() && + Fl::focus() == _tree && + prefs.selectmode() != FL_TREE_SELECT_NONE ) { + draw_item_focus(FL_NO_BOX,fg,bg,bg_x+1,bg_y+1,bg_w-1,bg_h-1); + } + } // end drawthis + } // end clipped + if ( drawthis ) Y += H2; // adjust Y (even if clipped) + // Manage tree_item_xmax + if ( ixmax > tree_item_xmax ) + tree_item_xmax = ixmax; + // Draw child items (if any) + if ( has_children() && is_open() ) { + int child_x = drawthis ? (hconn_x_center - (icon_w/2) + 1) // offset children to right, + : X; // unless didn't drawthis + int child_w = W - (child_x-X); + int child_y_start = Y; + for ( int t=0; t<children(); t++ ) { + int lastchild = ((t+1)==children()) ? 1 : 0; + _children[t]->draw(child_x, Y, child_w, itemfocus, tree_item_xmax, lastchild, render); + } + if ( has_children() && is_open() ) { + Y += prefs.openchild_marginbottom(); // offset below open child tree + } + if ( ! lastchild ) { + // Special 'clipped' calculation. (intentional variable shadowing) + int clipped = ((child_y_start < tree_top) && (Y < tree_top)) || + ((child_y_start > tree_bot) && (Y > tree_bot)); + if (render && !clipped ) + draw_vertical_connector(hconn_x, child_y_start, Y, prefs); + } + } +} + +#else + /// Draw this item and its children. +/// +/// \param[in] X Horizontal position for item being drawn +/// \param[in,out] Y Vertical position for item being drawn, returns new position for next item +/// \param[in] W Recommended width of item +/// \param[in] tree The parent tree +/// \param[in] itemfocus The tree's current focus item (if any) +/// \param[in] prefs The tree's preferences +/// \param[in] lastchild Is this item the last child in a subtree? +/// void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Widget *tree, Fl_Tree_Item *itemfocus, const Fl_Tree_Prefs &prefs, int lastchild) { @@ -802,8 +1063,9 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Widget *tree, } } } +#endif -/// Was the event on the 'collapse' button? +/// Was the event on the 'collapse' button of this item? /// int Fl_Tree_Item::event_on_collapse_icon(const Fl_Tree_Prefs &prefs) const { if ( is_visible() && is_active() && has_children() && prefs.showcollapse() ) { @@ -813,7 +1075,7 @@ int Fl_Tree_Item::event_on_collapse_icon(const Fl_Tree_Prefs &prefs) const { } } -/// Was event on the label()? +/// Was event on the label() of this item? /// int Fl_Tree_Item::event_on_label(const Fl_Tree_Prefs &prefs) const { if ( is_visible() && is_active() ) { @@ -852,6 +1114,7 @@ void Fl_Tree_Item::open() { for ( int t=0; t<_children.total(); t++ ) { _children[t]->show_widgets(); } + recalc_tree(); // may change tree geometry } /// Close this item and all its children. @@ -861,12 +1124,14 @@ void Fl_Tree_Item::close() { for ( int t=0; t<_children.total(); t++ ) { _children[t]->hide_widgets(); } + recalc_tree(); // may change tree geometry } /// Returns how many levels deep this item is in the hierarchy. /// /// For instance; root has a depth of zero, and its immediate children -/// would have a depth of 1, and so on. +/// would have a depth of 1, and so on. Use e.g. for determining the +/// horizontal indent of this item during drawing. /// int Fl_Tree_Item::depth() const { int count = 0; @@ -914,7 +1179,8 @@ Fl_Tree_Item *Fl_Tree_Item::next() { /// This method can be used to walk the tree backwards. /// For an example of how to use this method, see Fl_Tree::last(). /// -/// \returns the previous item in the tree, or 0 if there's no item above this one (hit the root). +/// \returns the previous item in the tree, +/// or 0 if there's no item above this one (hit the root). /// Fl_Tree_Item *Fl_Tree_Item::prev() { #if FLTK_ABI_VERSION >= 10301 @@ -965,7 +1231,7 @@ Fl_Tree_Item *Fl_Tree_Item::prev() { /// Return this item's next sibling. /// /// Moves to the next item below us at the same level (sibling). -/// Use this to move down the tree without moving deeper into the tree, +/// Use this to move down the tree without changing depth(). /// effectively skipping over this item's children/descendents. /// /// \returns item's next sibling, or 0 if none. @@ -988,7 +1254,7 @@ Fl_Tree_Item *Fl_Tree_Item::next_sibling() { /// Return this item's previous sibling. /// /// Moves to the previous item above us at the same level (sibling). -/// Use this to move up the tree without moving deeper into the tree. +/// Use this to move up the tree without changing depth(). /// /// \returns This item's previous sibling, or 0 if none. /// @@ -1006,7 +1272,7 @@ Fl_Tree_Item *Fl_Tree_Item::prev_sibling() { #endif /*FLTK_ABI_VERSION*/ } -/// Update our _prev_sibling and _next_sibling pointers to point to neighbors, +/// Update our _prev_sibling and _next_sibling pointers to point to neighbors /// given \p index as being our current position in the parent's item array. /// Call this whenever items in the array are added/removed/moved/swapped. /// @@ -1031,14 +1297,16 @@ void Fl_Tree_Item::update_prev_next(int index) { #endif /*FLTK_ABI_VERSION*/ } -/// Return the next visible item. (If this item has children and is closed, children are skipped) +/// Return the next open(), visible() item. +/// (If this item has children and is closed, children are skipped) /// /// This method can be used to walk the tree forward, skipping items -/// that are not currently visible to the user. +/// that are not currently open/visible to the user. /// -/// \returns the next visible item below us, or 0 if there's no more items. +/// \returns the next open() visible() item below us, +/// or 0 if there's no more items. /// -Fl_Tree_Item *Fl_Tree_Item::next_displayed(Fl_Tree_Prefs &prefs) { +Fl_Tree_Item *Fl_Tree_Item::next_visible(Fl_Tree_Prefs &prefs) { Fl_Tree_Item *item = this; while ( 1 ) { item = item->next(); @@ -1048,14 +1316,22 @@ Fl_Tree_Item *Fl_Tree_Item::next_displayed(Fl_Tree_Prefs &prefs) { } } -/// Return the previous visible item. (If this item above us has children and is closed, its children are skipped) +/// Same as next_visible(). +/// \deprecated in 1.3.3 ABI for confusing name, use next_visible() +Fl_Tree_Item *Fl_Tree_Item::next_displayed(Fl_Tree_Prefs &prefs) { + return next_visible(prefs); +} + +/// Return the previous open(), visible() item. +/// (If this item above us has children and is closed, its children are skipped) /// /// This method can be used to walk the tree backward, -/// skipping items that are not currently visible to the user. +/// skipping items that are not currently open/visible to the user. /// -/// \returns the previous visible item above us, or 0 if there's no more items. +/// \returns the previous open() visible() item above us, +/// or 0 if there's no more items. /// -Fl_Tree_Item *Fl_Tree_Item::prev_displayed(Fl_Tree_Prefs &prefs) { +Fl_Tree_Item *Fl_Tree_Item::prev_visible(Fl_Tree_Prefs &prefs) { Fl_Tree_Item *c = this; while ( c ) { c = c->prev(); // previous item @@ -1075,11 +1351,17 @@ Fl_Tree_Item *Fl_Tree_Item::prev_displayed(Fl_Tree_Prefs &prefs) { return(0); // hit end: no more items } -/// Returns if item and all its parents are visible. -/// Also takes into consideration if any parent is close()ed. +/// Same as prev_visible(). +/// \deprecated in 1.3.3 ABI for confusing name, use prev_visible() +/// +Fl_Tree_Item *Fl_Tree_Item::prev_displayed(Fl_Tree_Prefs &prefs) { + return prev_visible(prefs); +} + +/// See if item and all its parents are open() and visible(). /// \returns -/// 1 -- item and its parents are visible/open() -/// 0 -- item (or parents) invisible or close()ed. +/// 1 -- item and its parents are open() and visible() +/// 0 -- item (or one of its parents) are invisible or close()ed. /// int Fl_Tree_Item::visible_r() const { if ( !visible() ) return(0); @@ -1088,6 +1370,16 @@ int Fl_Tree_Item::visible_r() const { return(1); } +/// Call this when our geometry is changed. (Font size, label contents, etc) +/// Schedules tree to recalculate itself, as changes to us may affect tree +/// widget's scrollbar visibility and tab sizes. +/// +void Fl_Tree_Item::recalc_tree() { +#if FLTK_ABI_VERSION >= 10303 + _tree->recalc_tree(); +#endif +} + // // End of "$Id$". // |
