fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

Fl_Tree_Item.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: Fl_Tree_Item.cxx 7903 2010-11-28 21:06:39Z matt $"
00003 //
00004 
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <string.h>
00008 #include <FL/Fl_Widget.H>
00009 #include <FL/Fl_Tree_Item.H>
00010 #include <FL/Fl_Tree_Prefs.H>
00011 
00013 // Fl_Tree_Item.cxx
00015 //
00016 // Fl_Tree -- This file is part of the Fl_Tree widget for FLTK
00017 // Copyright (C) 2009-2010 by Greg Ercolano.
00018 //
00019 // This library is free software; you can redistribute it and/or
00020 // modify it under the terms of the GNU Library General Public
00021 // License as published by the Free Software Foundation; either
00022 // version 2 of the License, or (at your option) any later version.
00023 //
00024 // This library is distributed in the hope that it will be useful,
00025 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00026 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00027 // Library General Public License for more details.
00028 //
00029 // You should have received a copy of the GNU Library General Public
00030 // License along with this library; if not, write to the Free Software
00031 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00032 // USA.
00033 //
00034 
00035 // Was the last event inside the specified xywh?
00036 static int event_inside(const int xywh[4]) {
00037   return(Fl::event_inside(xywh[0],xywh[1],xywh[2],xywh[3]));
00038 }
00039 
00043 Fl_Tree_Item::Fl_Tree_Item(const Fl_Tree_Prefs &prefs) {
00044   _label        = 0;
00045   _labelfont    = prefs.labelfont();
00046   _labelsize    = prefs.labelsize();
00047   _labelfgcolor = prefs.fgcolor();
00048   _labelbgcolor = prefs.bgcolor();
00049   _widget       = 0;
00050   _open         = 1;
00051   _visible      = 1;
00052   _active       = 1;
00053   _selected     = 0;
00054   _xywh[0]      = 0;
00055   _xywh[1]      = 0;
00056   _xywh[2]      = 0;
00057   _xywh[3]      = 0;
00058   _collapse_xywh[0] = 0;
00059   _collapse_xywh[1] = 0;
00060   _collapse_xywh[2] = 0;
00061   _collapse_xywh[3] = 0;
00062   _label_xywh[0]    = 0;
00063   _label_xywh[1]    = 0;
00064   _label_xywh[2]    = 0;
00065   _label_xywh[3]    = 0;
00066   _usericon         = 0;
00067   _userdata         = 0;
00068   _parent           = 0;
00069 }
00070 
00071 // DTOR
00072 Fl_Tree_Item::~Fl_Tree_Item() {
00073   if ( _label ) { 
00074     free((void*)_label);
00075     _label = 0;
00076   }
00077   _widget = 0;                  // Fl_Group will handle destruction
00078   _usericon = 0;                // user handled allocation
00079   //_children.clear();          // array's destructor handles itself
00080 }
00081 
00083 Fl_Tree_Item::Fl_Tree_Item(const Fl_Tree_Item *o) {
00084   _label        = o->label() ? strdup(o->label()) : 0;
00085   _labelfont    = o->labelfont();
00086   _labelsize    = o->labelsize();
00087   _labelfgcolor = o->labelfgcolor();
00088   _labelbgcolor = o->labelbgcolor();
00089   _widget       = o->widget();
00090   _open         = o->_open;
00091   _visible      = o->_visible;
00092   _active       = o->_active;
00093   _selected     = o->_selected;
00094   _xywh[0]      = o->_xywh[0];
00095   _xywh[1]      = o->_xywh[1];
00096   _xywh[2]      = o->_xywh[2];
00097   _xywh[3]      = o->_xywh[3];
00098   _collapse_xywh[0] = o->_collapse_xywh[0];
00099   _collapse_xywh[1] = o->_collapse_xywh[1];
00100   _collapse_xywh[2] = o->_collapse_xywh[2];
00101   _collapse_xywh[3] = o->_collapse_xywh[3];
00102   _label_xywh[0]    = o->_label_xywh[0];
00103   _label_xywh[1]    = o->_label_xywh[1];
00104   _label_xywh[2]    = o->_label_xywh[2];
00105   _label_xywh[3]    = o->_label_xywh[3];
00106   _usericon         = o->usericon();
00107   _userdata         = o->user_data();
00108   _parent           = o->_parent;
00109 }
00110 
00114 void Fl_Tree_Item::show_self(const char *indent) const {
00115   if ( label() ) {
00116     printf("%s-%s (%d children, this=%p, parent=%p depth=%d)\n",
00117            indent,label(),children(),(void*)this, (void*)_parent, depth());
00118   }
00119   if ( children() ) {
00120     char *i2 = (char*)malloc(strlen(indent) + 2);
00121     strcpy(i2, indent);
00122     strcat(i2, " |");
00123     for ( int t=0; t<children(); t++ ) {
00124       child(t)->show_self(i2);
00125     }
00126   }
00127   fflush(stdout);
00128 }
00129 
00131 void Fl_Tree_Item::label(const char *name) {
00132   if ( _label ) { free((void*)_label); _label = 0; }
00133   _label = name ? strdup(name) : 0;
00134 }
00135 
00137 const char *Fl_Tree_Item::label() const {
00138   return(_label);
00139 }
00140 
00142 const Fl_Tree_Item *Fl_Tree_Item::child(int index) const {
00143   return(_children[index]);
00144 }
00145 
00147 void Fl_Tree_Item::clear_children() {
00148   _children.clear();
00149 }
00150 
00155 int Fl_Tree_Item::find_child(const char *name) {
00156   if ( name ) {
00157     for ( int t=0; t<children(); t++ ) {
00158       if ( child(t)->label() ) {
00159         if ( strcmp(child(t)->label(), name) == 0 ) {
00160           return(t);
00161         }
00162       }
00163     }
00164   }
00165   return(-1);
00166 }
00167 
00173 const Fl_Tree_Item *Fl_Tree_Item::find_child_item(char **arr) const {
00174   for ( int t=0; t<children(); t++ ) {
00175     if ( child(t)->label() ) {
00176       if ( strcmp(child(t)->label(), *arr) == 0 ) {     // match?
00177         if ( *(arr+1) ) {                               // more in arr? descend
00178           return(_children[t]->find_item(arr+1));
00179         } else {                                        // end of arr? done
00180           return(_children[t]);
00181         }
00182       }
00183     }
00184   }
00185   return(0);
00186 }
00187 
00193 Fl_Tree_Item *Fl_Tree_Item::find_child_item(char **arr) {
00194   for ( int t=0; t<children(); t++ ) {
00195     if ( child(t)->label() ) {
00196       if ( strcmp(child(t)->label(), *arr) == 0 ) {     // match?
00197         if ( *(arr+1) ) {                               // more in arr? descend
00198           return(_children[t]->find_item(arr+1));
00199         } else {                                        // end of arr? done
00200           return(_children[t]);
00201         }
00202       }
00203     }
00204   }
00205   return(0);
00206 }
00207 
00213 const Fl_Tree_Item *Fl_Tree_Item::find_item(char **names) const {
00214   if ( label() && strcmp(label(), *names) == 0 ) {      // match self?
00215     if ( *(names+1) == 0 ) {                            // end of names,
00216       return(this);                                     // found ourself.
00217     }
00218   }
00219   if ( children() ) {                                   // check children..
00220     return(find_child_item(names));
00221   }
00222   return(0);
00223 }
00224 
00230 Fl_Tree_Item *Fl_Tree_Item::find_item(char **names) {
00231   if ( label() && strcmp(label(), *names) == 0 ) {      // match self?
00232     if ( *(names+1) == 0 ) {                            // end of names,
00233       return(this);                                     // found ourself.
00234     }
00235   }
00236   if ( children() ) {                                   // check children..
00237     return(find_child_item(names));
00238   }
00239   return(0);
00240 }
00241 
00247 int Fl_Tree_Item::find_child(Fl_Tree_Item *item) {
00248   for ( int t=0; t<children(); t++ ) {
00249     if ( item == child(t) ) {
00250       return(t);
00251     }
00252   }
00253   return(-1);
00254 }
00255 
00260 Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs, const char *new_label) {
00261   Fl_Tree_Item *item = new Fl_Tree_Item(prefs);
00262   item->label(new_label);
00263   item->_parent = this;
00264   switch ( prefs.sortorder() ) {
00265     case FL_TREE_SORT_NONE: {
00266       _children.add(item);
00267       return(item);
00268     }
00269     case FL_TREE_SORT_ASCENDING: {
00270       for ( int t=0; t<_children.total(); t++ ) {
00271         Fl_Tree_Item *c = _children[t];
00272         if ( c->label() && strcmp(c->label(), new_label) > 0 ) {
00273           _children.insert(t, item);
00274           return(item);
00275         }
00276       }
00277       _children.add(item);
00278       return(item);
00279     }
00280     case FL_TREE_SORT_DESCENDING: {
00281       for ( int t=0; t<_children.total(); t++ ) {
00282         Fl_Tree_Item *c = _children[t];
00283         if ( c->label() && strcmp(c->label(), new_label) < 0 ) {
00284           _children.insert(t, item);
00285           return(item);
00286         }
00287       }
00288       _children.add(item);
00289       return(item);
00290     }
00291   }
00292   return(item);
00293 }
00294 
00300 Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs, char **arr) {
00301   int t = find_child(*arr);
00302   Fl_Tree_Item *item;
00303   if ( t == -1 ) {
00304     item = (Fl_Tree_Item*)add(prefs, *arr);
00305   } else {
00306     item = (Fl_Tree_Item*)child(t);
00307   }
00308   if ( *(arr+1) ) {             // descend?
00309     return(item->add(prefs, arr+1));
00310   } else {
00311     return(item);               // end? done
00312   }
00313 }
00314 
00318 Fl_Tree_Item *Fl_Tree_Item::insert(const Fl_Tree_Prefs &prefs, const char *new_label, int pos) {
00319   Fl_Tree_Item *item = new Fl_Tree_Item(prefs);
00320   item->label(new_label);
00321   item->_parent = this;
00322   _children.insert(pos, item);
00323   return(item);
00324 }
00325 
00329 Fl_Tree_Item *Fl_Tree_Item::insert_above(const Fl_Tree_Prefs &prefs, const char *new_label) {
00330   Fl_Tree_Item *p = _parent;
00331   if ( ! p ) return(0);
00332   // Walk our parent's children to find ourself
00333   for ( int t=0; t<p->children(); t++ ) {
00334     Fl_Tree_Item *c = p->child(t);
00335     if ( this == c ) {
00336       return(p->insert(prefs, new_label, t));
00337     }
00338   }
00339   return(0);
00340 }
00341 
00345 int Fl_Tree_Item::remove_child(Fl_Tree_Item *item) {
00346   for ( int t=0; t<children(); t++ ) {
00347     if ( child(t) == item ) {
00348       item->clear_children();
00349       _children.remove(t);
00350       return(0);
00351     }
00352   }
00353   return(-1);
00354 }
00355 
00359 int Fl_Tree_Item::remove_child(const char *name) {
00360   for ( int t=0; t<children(); t++ ) {
00361     if ( child(t)->label() ) {
00362       if ( strcmp(child(t)->label(), name) == 0 ) {
00363         _children.remove(t);
00364         return(0);
00365       }
00366     }
00367   }
00368   return(-1);
00369 }
00370 
00382 void Fl_Tree_Item::swap_children(int ax, int bx) {
00383   _children.swap(ax, bx);
00384 }
00385 
00396 int Fl_Tree_Item::swap_children(Fl_Tree_Item *a, Fl_Tree_Item *b) {
00397   int ax = -1, bx = -1;
00398   for ( int t=0; t<children(); t++ ) {  // find index for a and b
00399     if ( _children[t] == a ) { ax = t; if ( bx != -1 ) break; else continue; }
00400     if ( _children[t] == b ) { bx = t; if ( ax != -1 ) break; else continue; }
00401   }
00402   if ( ax == -1 || bx == -1 ) return(-1);       // not found? fail
00403   swap_children(ax,bx);
00404   return(0);
00405 }
00406 
00408 void Fl_Tree_Item::draw_horizontal_connector(int x1, int x2, int y, const Fl_Tree_Prefs &prefs) {
00409   fl_color(prefs.connectorcolor());
00410   switch ( prefs.connectorstyle() ) {
00411     case FL_TREE_CONNECTOR_SOLID:
00412       y |= 1;                           // force alignment w/dot pattern
00413       fl_line(x1,y,x2,y);
00414       return;
00415     case FL_TREE_CONNECTOR_DOTTED: 
00416         {
00417             y |= 1;                             // force alignment w/dot pattern
00418             for ( int xx=x1; xx<=x2; xx++ ) {
00419                 if ( !(xx & 1) ) fl_point(xx, y);
00420             }
00421         }
00422       return;
00423     case FL_TREE_CONNECTOR_NONE:
00424       return;
00425   }
00426 }
00427 
00429 void Fl_Tree_Item::draw_vertical_connector(int x, int y1, int y2, const Fl_Tree_Prefs &prefs) {
00430   fl_color(prefs.connectorcolor());
00431   switch ( prefs.connectorstyle() ) {
00432     case FL_TREE_CONNECTOR_SOLID:
00433       y1 |= 1;                          // force alignment w/dot pattern
00434       y2 |= 1;                          // force alignment w/dot pattern
00435       fl_line(x,y1,x,y2);
00436       return;
00437     case FL_TREE_CONNECTOR_DOTTED:
00438         {
00439             y1 |= 1;                            // force alignment w/dot pattern
00440             y2 |= 1;                            // force alignment w/dot pattern
00441             for ( int yy=y1; yy<=y2; yy++ ) {
00442                 if ( yy & 1 ) fl_point(x, yy);
00443             }
00444         }
00445         return;
00446     case FL_TREE_CONNECTOR_NONE:
00447       return;
00448   }
00449 }
00450 
00459 const Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs) const {
00460   if ( ! _visible ) return(0);
00461   if ( is_root() && !prefs.showroot() ) {
00462     // skip event check if we're root but root not being shown
00463   } else {
00464     // See if event is over us
00465     if ( event_inside(_xywh) ) {                // event within this item?
00466       return(this);                             // found
00467     }
00468   }
00469   if ( is_open() ) {                            // open? check children of this item
00470     for ( int t=0; t<children(); t++ ) {
00471       const Fl_Tree_Item *item;
00472       if ( ( item = _children[t]->find_clicked(prefs) ) != NULL) {      // check child and its descendents
00473         return(item);                                                   // found?
00474       }
00475     }
00476   }
00477   return(0);
00478 }
00479 
00489 Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs) {
00490   if ( ! _visible ) return(0);
00491   if ( is_root() && !prefs.showroot() ) {
00492     // skip event check if we're root but root not being shown
00493   } else {
00494     // See if event is over us
00495     if ( event_inside(_xywh) ) {                // event within this item?
00496       return(this);                             // found
00497     }
00498   }
00499   if ( is_open() ) {                            // open? check children of this item
00500     for ( int t=0; t<children(); t++ ) {
00501       Fl_Tree_Item *item;
00502       if ( ( item = _children[t]->find_clicked(prefs) ) != NULL ) {     // check child and its descendents
00503         return(item);                                                   // found?
00504       }
00505     }
00506   }
00507   return(0);
00508 }
00509 
00510 static void draw_item_focus(Fl_Boxtype B, Fl_Color C, int X, int Y, int W, int H) {
00511   if (!Fl::visible_focus()) return;
00512   switch (B) {
00513     case FL_DOWN_BOX:
00514     case FL_DOWN_FRAME:
00515     case FL_THIN_DOWN_BOX:
00516     case FL_THIN_DOWN_FRAME:
00517       X ++;
00518       Y ++;
00519     default:
00520       break;
00521   }
00522   fl_color(fl_contrast(FL_BLACK, C));
00523 
00524 #if defined(USE_X11) || defined(__APPLE_QUARTZ__)
00525   fl_line_style(FL_DOT);
00526   fl_rect(X + Fl::box_dx(B), Y + Fl::box_dy(B),
00527           W - Fl::box_dw(B) - 1, H - Fl::box_dh(B) - 1);
00528   fl_line_style(FL_SOLID);
00529 #else
00530   // Some platforms don't implement dotted line style, so draw
00531   // every other pixel around the focus area...
00532   //
00533   // Also, QuickDraw (MacOS) does not support line styles specifically,
00534   // and the hack we use in fl_line_style() will not draw horizontal lines
00535   // on odd-numbered rows...
00536   int i, xx, yy;
00537 
00538   X += Fl::box_dx(B);
00539   Y += Fl::box_dy(B);
00540   W -= Fl::box_dw(B) + 2;
00541   H -= Fl::box_dh(B) + 2;
00542 
00543   for (xx = 0, i = 1; xx < W; xx ++, i ++) if (i & 1) fl_point(X + xx, Y);
00544   for (yy = 0; yy < H; yy ++, i ++) if (i & 1) fl_point(X + W, Y + yy);
00545   for (xx = W; xx > 0; xx --, i ++) if (i & 1) fl_point(X + xx, Y + H);
00546   for (yy = H; yy > 0; yy --, i ++) if (i & 1) fl_point(X, Y + yy);
00547 #endif
00548 }
00549 
00551 void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Widget *tree,
00552                         Fl_Tree_Item *itemfocus,
00553                         const Fl_Tree_Prefs &prefs, int lastchild) {
00554   if ( ! _visible ) return; 
00555   fl_font(_labelfont, _labelsize);
00556   int H = _labelsize;
00557   if(usericon() && H < usericon()->h()) H = usericon()->h(); 
00558   H += prefs.linespacing() + fl_descent();
00559   // adjust horizontally if we draw no connecting lines
00560   if ( is_root() && prefs.connectorstyle() == FL_TREE_CONNECTOR_NONE ) {
00561     X -= prefs.openicon()->w();
00562     W += prefs.openicon()->w();
00563   }
00564   // Colors, fonts
00565   Fl_Color fg = _selected ? prefs.bgcolor()     : _labelfgcolor;
00566   Fl_Color bg = _selected ? prefs.selectcolor() : _labelbgcolor;
00567   if ( ! _active ) {
00568     fg = fl_inactive(fg);
00569     if ( _selected ) bg = fl_inactive(bg);
00570   }
00571   // Update the xywh of this item
00572   _xywh[0] = X;
00573   _xywh[1] = Y;
00574   _xywh[2] = W;
00575   _xywh[3] = H;
00576   // Text size
00577   int textw=0, texth=0;
00578   fl_measure(_label, textw, texth, 0);
00579   int textycenter = Y+(H/2);
00580   int &icon_w = _collapse_xywh[2] = prefs.openicon()->w();
00581   int &icon_x = _collapse_xywh[0] = X + (icon_w + prefs.connectorwidth())/2 - 3;
00582   int &icon_y = _collapse_xywh[1] = textycenter - (prefs.openicon()->h()/2);
00583   _collapse_xywh[3] = prefs.openicon()->h();
00584   // Horizontal connector values
00585   int hstartx  = X+icon_w/2-1;
00586   int hendx    = hstartx + prefs.connectorwidth();
00587   int hcenterx = X + icon_w + ((hendx - (X + icon_w)) / 2);
00588   
00589   // See if we should draw this item
00590   //    If this item is root, and showroot() is disabled, don't draw.
00591   //
00592   char drawthis = ( is_root() && prefs.showroot() == 0 ) ? 0 : 1;
00593   if ( drawthis ) {
00594     // Draw connectors
00595     if ( prefs.connectorstyle() != FL_TREE_CONNECTOR_NONE ) {
00596       // Horiz connector between center of icon and text
00597       // if this is root, the connector should not dangle in thin air on the left
00598       if (is_root())
00599         draw_horizontal_connector(hcenterx, hendx, textycenter, prefs);
00600       else
00601         draw_horizontal_connector(hstartx, hendx, textycenter, prefs);
00602       if ( has_children() && is_open() ) {
00603         // Small vertical line down to children
00604         draw_vertical_connector(hcenterx, textycenter, Y+H, prefs);
00605       }
00606       // Connectors for last child
00607       if ( ! is_root() ) {
00608         if ( lastchild ) {
00609           draw_vertical_connector(hstartx, Y, textycenter, prefs);
00610         } else {
00611           draw_vertical_connector(hstartx, Y, Y+H, prefs);
00612         }
00613       }
00614     } 
00615     // Draw collapse icon
00616     if ( has_children() && prefs.showcollapse() ) {
00617       // Draw icon image
00618       if ( is_open() ) {
00619         prefs.closeicon()->draw(icon_x,icon_y);
00620       } else {
00621         prefs.openicon()->draw(icon_x,icon_y);
00622       }
00623     }
00624     // Background for this item
00625     int cw1 = icon_w+prefs.connectorwidth()/2, cw2 = prefs.connectorwidth();
00626     int cwidth = cw1>cw2 ? cw1 : cw2;
00627     int &bx = _label_xywh[0] = X+(icon_w/2-1+cwidth);
00628     int &by = _label_xywh[1] = Y;
00629     int &bw = _label_xywh[2] = W-(icon_w/2-1+cwidth);
00630     int &bh = _label_xywh[3] = H;
00631     // Draw bg only if different from tree's bg
00632     if ( bg != tree->color() || is_selected() ) {
00633       if ( is_selected() ) {
00634         // Selected? Use selectbox() style
00635         fl_draw_box(prefs.selectbox(), bx, by, bw, bh, bg);
00636       } else {
00637         // Not Selected? use plain filled rectangle
00638         fl_color(bg);
00639         fl_rectf(bx, by, bw, bh);
00640       }
00641     }
00642     // Draw user icon (if any)
00643     int useroff = (icon_w/2-1+cwidth);
00644     if ( usericon() ) {
00645       // Item has user icon? Use it
00646       useroff += prefs.usericonmarginleft();
00647       icon_y = textycenter - (usericon()->h() >> 1);
00648       usericon()->draw(X+useroff,icon_y);
00649       useroff += usericon()->w();
00650     } else if ( prefs.usericon() ) {
00651       // Prefs has user icon? Use it
00652       useroff += prefs.usericonmarginleft();
00653       icon_y = textycenter - (prefs.usericon()->h() >> 1);
00654       prefs.usericon()->draw(X+useroff,icon_y);
00655       useroff += prefs.usericon()->w();
00656     }
00657     useroff += prefs.labelmarginleft();
00658     // Draw label
00659     if ( widget() ) {
00660       // Widget? Draw it
00661       int lx = X+useroff;
00662       int ly = by;
00663       int lw = widget()->w();
00664       int lh = bh;
00665       if ( widget()->x() != lx || widget()->y() != ly ||
00666           widget()->w() != lw || widget()->h() != lh ) {
00667         widget()->resize(lx, ly, lw, lh);               // fltk will handle drawing this
00668       }
00669     } else {
00670       // No label widget? Draw text label
00671       if ( _label ) {
00672         fl_color(fg);
00673         fl_draw(_label, X+useroff, Y+H-fl_descent()-1);
00674       }
00675     }
00676     if ( this == itemfocus && Fl::visible_focus() && Fl::focus() == tree) {
00677       // Draw focus box around this item
00678       draw_item_focus(FL_NO_BOX,bg,bx+1,by+1,bw-1,bh-1);
00679     }
00680     Y += H;
00681   }                     // end drawthis
00682   // Draw children
00683   if ( has_children() && is_open() ) {
00684     int child_x = drawthis ?                            // offset children to right,
00685     (hcenterx - (icon_w/2) + 1) : X;                    // unless didn't drawthis
00686     int child_w = W - (child_x-X);
00687     int child_y_start = Y;
00688     for ( int t=0; t<children(); t++ ) {
00689       int lastchild = ((t+1)==children()) ? 1 : 0;
00690       _children[t]->draw(child_x, Y, child_w, tree, itemfocus, prefs, lastchild);
00691     }
00692     if ( has_children() && is_open() ) {
00693       Y += prefs.openchild_marginbottom();              // offset below open child tree
00694     }
00695     if ( ! lastchild ) {
00696       draw_vertical_connector(hstartx, child_y_start, Y, prefs);
00697     }
00698   }
00699 }
00700 
00703 int Fl_Tree_Item::event_on_collapse_icon(const Fl_Tree_Prefs &prefs) const {
00704   if ( _visible && _active && has_children() && prefs.showcollapse() ) {
00705     return(event_inside(_collapse_xywh) ? 1 : 0);
00706   } else {
00707     return(0);
00708   }
00709 }
00710 
00713 int Fl_Tree_Item::event_on_label(const Fl_Tree_Prefs &prefs) const {
00714   if ( _visible && _active ) {
00715     return(event_inside(_label_xywh) ? 1 : 0);
00716   } else {
00717     return(0);
00718   }
00719 }
00720 
00724 void Fl_Tree_Item::show_widgets() {
00725   if ( _widget ) _widget->show();
00726   if ( is_open() ) {
00727     for ( int t=0; t<_children.total(); t++ ) {
00728       _children[t]->show_widgets();
00729     }
00730   }
00731 }
00732 
00736 void Fl_Tree_Item::hide_widgets() {
00737   if ( _widget ) _widget->hide();
00738   for ( int t=0; t<_children.total(); t++ ) {
00739     _children[t]->hide_widgets();
00740   }
00741 }
00742 
00744 void Fl_Tree_Item::open() {
00745   _open = 1;
00746   // Tell children to show() their widgets
00747   for ( int t=0; t<_children.total(); t++ ) {
00748     _children[t]->show_widgets();
00749   }
00750 }
00751 
00753 void Fl_Tree_Item::close() {
00754   _open = 0;
00755   // Tell children to hide() their widgets
00756   for ( int t=0; t<_children.total(); t++ ) {
00757     _children[t]->hide_widgets();
00758   }
00759 }
00760 
00766 int Fl_Tree_Item::depth() const {
00767   int count = 0;
00768   const Fl_Tree_Item *item = parent();
00769   while ( item ) {
00770     ++count;
00771     item = item->parent();
00772   }
00773   return(count);
00774 }
00775 
00783 Fl_Tree_Item *Fl_Tree_Item::next() {
00784   Fl_Tree_Item *p, *c = this;
00785   if ( c->has_children() ) {
00786     return(c->child(0));
00787   }
00788   while ( ( p = c->parent() ) != NULL ) {       // loop upwards through parents
00789     int t = p->find_child(c);                   // find our position in parent's children[] array
00790     if ( ++t < p->children() )                  // not last child?
00791       return(p->child(t));                      // return next child
00792     c = p;                                      // child becomes parent to move up generation
00793   }                                             // loop: moves up to next parent
00794   return(0);                                    // hit root? done
00795 }
00796 
00804 Fl_Tree_Item *Fl_Tree_Item::prev() {
00805   Fl_Tree_Item *p=parent();             // start with parent
00806   if ( ! p ) return(0);                 // hit root? done
00807   int t = p->find_child(this);          // find our position in parent's children[] array
00808   if ( --t == -1 ) {                    // are we first child?
00809     return(p);                          // return immediate parent
00810   }
00811   p = p->child(t);                      // take parent's previous child
00812   while ( p->has_children() ) {         // has children?
00813     p = p->child(p->children()-1);      // take last child
00814   }
00815   return(p);
00816 }
00817 
00826 Fl_Tree_Item *Fl_Tree_Item::next_sibling() {
00827   if ( !parent() ) return(0);                   // No parent (root)? We have no siblings
00828   int index = parent()->find_child(this);       // find our position in parent's child() array
00829   if ( index == -1 ) return(0);                 // parent doesn't know us? weird
00830   if ( (index+1) < parent()->children() )       // is there a next child?
00831     return(parent()->child(index+1));           // return next child if there's one below us
00832   return(0);                                    // no siblings below us
00833 }
00834 
00842 Fl_Tree_Item *Fl_Tree_Item::prev_sibling() {
00843   if ( !parent() ) return(0);                           // No parent (root)? We have no siblings
00844   int index = parent()->find_child(this);               // find next position up in parent's child() array
00845   if ( index == -1 ) return(0);                         // parent doesn't know us? weird
00846   if ( index > 0 ) return(parent()->child(index-1));    // return previous child if there's one above us
00847   return(0);                                            // no siblings above us
00848 }
00849 
00857 Fl_Tree_Item *Fl_Tree_Item::next_displayed(Fl_Tree_Prefs &prefs) {
00858   Fl_Tree_Item *c = this;
00859   while ( c ) {
00860     if ( c->is_root() && !prefs.showroot() ) {          // on root and can't show it?
00861       c = c->next();                                    // skip ahead, try again
00862       continue;
00863     }
00864     if ( c->has_children() && c->is_close() ) {         // item has children and: invisible or closed?
00865       // Skip children, take next sibling. If none, try parent's sibling, repeat
00866       while ( c ) {
00867         Fl_Tree_Item *sib = c->next_sibling();          // get sibling
00868         if ( sib ) { c = sib; break; }                  // Found? let outer loop test it
00869         c = c->parent();                                // No sibling? move up tree, try parent's sibling
00870       }
00871     } else {                                            // has children and isn't closed, or no children
00872       c = c->next();                                    // use normal 'next'
00873     }
00874     if ( !c ) return(0);                                // no more? done
00875     // Check all parents to be sure none are closed.
00876     // If closed, move up to that level and repeat until sure none are closed.
00877     Fl_Tree_Item *p = c->parent();
00878     while (1) {
00879       if ( !p || p->is_root() ) return(c);              // hit top? then we're displayed, return c
00880       if ( p->is_close() ) c = p;                       // found closed parent? make it current
00881       p = p->parent();                                  // continue up tree
00882     }
00883     if ( c && c->visible() ) return(c);                 // item visible? return it
00884   }
00885   return(0);                                            // hit end: no more items
00886 }
00887 
00895 Fl_Tree_Item *Fl_Tree_Item::prev_displayed(Fl_Tree_Prefs &prefs) {
00896   Fl_Tree_Item *c = this;
00897   while ( c ) {
00898     c = c->prev();                                      // previous item
00899     if ( !c ) break;                                    // no more items? done
00900     if ( c->is_root() )                                 // root
00901       return((prefs.showroot()&&c->visible()) ? c : 0); // return root if visible
00902     if ( !c->visible() ) continue;                      // item not visible? skip
00903     // Check all parents to be sure none are closed.
00904     // If closed, move up to that level and repeat until sure none are closed.
00905     Fl_Tree_Item *p = c->parent();
00906     while (1) {
00907       if ( !p || p->is_root() ) return(c);              // hit top? then we're displayed, return c
00908       if ( p->is_close() ) c = p;                       // found closed parent? make it current
00909       p = p->parent();                                  // continue up tree
00910     }
00911   }
00912   return(0);                                            // hit end: no more items
00913 }
00914 
00921 int Fl_Tree_Item::visible_r() const {
00922   for (const Fl_Tree_Item *p=this; p; p=p->parent())    // move up through parents
00923     if (!p->visible() || p->is_close()) return(0);      // any parent not visible or closed?
00924   return(1);
00925 }
00926 
00927 //
00928 // End of "$Id: Fl_Tree_Item.cxx 7903 2010-11-28 21:06:39Z matt $".
00929 //