|
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) ![]() |
00001 // 00002 // "$Id: Fl_Tree.cxx 7903 2010-11-28 21:06:39Z matt $" 00003 // 00004 00005 #include <stdio.h> 00006 #include <stdlib.h> 00007 #include <string.h> 00008 00009 #include <FL/Fl_Tree.H> 00010 #include <FL/Fl_Preferences.H> 00011 00013 // Fl_Tree.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 // INTERNAL: scroller callback 00036 static void scroll_cb(Fl_Widget*,void *data) { 00037 ((Fl_Tree*)data)->redraw(); 00038 } 00039 00040 // INTERNAL: Parse elements from path into an array of null terminated strings 00041 // Path="/aa/bb" 00042 // Return: arr[0]="aa", arr[1]="bb", arr[2]=0 00043 // Caller must call free_path(arr). 00044 // 00045 static char **parse_path(const char *path) { 00046 while ( *path == '/' ) path++; // skip leading '/' 00047 // First pass: identify, null terminate, and count separators 00048 int seps = 1; // separator count (1: first item) 00049 int arrsize = 1; // array size (1: first item) 00050 char *save = strdup(path); // make copy we can modify 00051 char *s = save; 00052 while ( ( s = strchr(s, '/') ) ) { 00053 while ( *s == '/' ) { *s++ = 0; seps++; } 00054 if ( *s ) { arrsize++; } 00055 } 00056 arrsize++; // (room for terminating NULL) 00057 // Second pass: create array, save nonblank elements 00058 char **arr = (char**)malloc(sizeof(char*) * arrsize); 00059 int t = 0; 00060 s = save; 00061 while ( seps-- > 0 ) { 00062 if ( *s ) { arr[t++] = s; } // skips empty fields, eg. '//' 00063 s += (strlen(s) + 1); 00064 } 00065 arr[t] = 0; 00066 return(arr); 00067 } 00068 00069 // INTERNAL: Free the array returned by parse_path() 00070 static void free_path(char **arr) { 00071 if ( arr ) { 00072 if ( arr[0] ) { free((void*)arr[0]); } 00073 free((void*)arr); 00074 } 00075 } 00076 00077 // INTERNAL: Recursively descend tree hierarchy, accumulating total child count 00078 static int find_total_children(Fl_Tree_Item *item, int count=0) { 00079 count++; 00080 for ( int t=0; t<item->children(); t++ ) { 00081 count = find_total_children(item->child(t), count); 00082 } 00083 return(count); 00084 } 00085 00087 Fl_Tree::Fl_Tree(int X, int Y, int W, int H, const char *L) : Fl_Group(X,Y,W,H,L) { 00088 _root = new Fl_Tree_Item(_prefs); 00089 _root->parent(0); // we are root of tree 00090 _root->label("ROOT"); 00091 _item_focus = 0; 00092 _callback_item = 0; 00093 _callback_reason = FL_TREE_REASON_NONE; 00094 _scrollbar_size = 0; // 0: uses Fl::scrollbar_size() 00095 box(FL_DOWN_BOX); 00096 color(FL_WHITE); 00097 when(FL_WHEN_CHANGED); 00098 _vscroll = new Fl_Scrollbar(0,0,0,0); // will be resized by draw() 00099 _vscroll->hide(); 00100 _vscroll->type(FL_VERTICAL); 00101 _vscroll->step(1); 00102 _vscroll->callback(scroll_cb, (void*)this); 00103 end(); 00104 } 00105 00107 Fl_Tree::~Fl_Tree() { 00108 if ( _root ) { delete _root; _root = 0; } 00109 } 00110 00116 Fl_Tree_Item* Fl_Tree::add(const char *path) { 00117 if ( ! _root ) { // Create root if none 00118 _root = new Fl_Tree_Item(_prefs); 00119 _root->parent(0); 00120 _root->label("ROOT"); 00121 } 00122 char **arr = parse_path(path); 00123 Fl_Tree_Item *item = _root->add(_prefs, arr); 00124 free_path(arr); 00125 return(item); 00126 } 00127 00131 Fl_Tree_Item* Fl_Tree::insert_above(Fl_Tree_Item *above, const char *name) { 00132 return(above->insert_above(_prefs, name)); 00133 } 00134 00142 Fl_Tree_Item* Fl_Tree::insert(Fl_Tree_Item *item, const char *name, int pos) { 00143 return(item->insert(_prefs, name, pos)); 00144 } 00145 00152 Fl_Tree_Item* Fl_Tree::add(Fl_Tree_Item *item, const char *name) { 00153 return(item->add(_prefs, name)); 00154 } 00155 00167 Fl_Tree_Item *Fl_Tree::find_item(const char *path) { 00168 if ( ! _root ) return(0); 00169 char **arr = parse_path(path); 00170 Fl_Tree_Item *item = _root->find_item(arr); 00171 free_path(arr); 00172 return(item); 00173 } 00174 00176 const Fl_Tree_Item *Fl_Tree::find_item(const char *path) const { 00177 if ( ! _root ) return(0); 00178 char **arr = parse_path(path); 00179 const Fl_Tree_Item *item = _root->find_item(arr); 00180 free_path(arr); 00181 return(item); 00182 } 00183 00184 // Handle safe 'reverse string concatenation'. 00185 // In the following we build the pathname from right-to-left, 00186 // since we start at the child and work our way up to the root. 00187 // 00188 #define SAFE_RCAT(c) { \ 00189 slen += 1; if ( slen >= pathnamelen ) { pathname[0] = '\0'; return(-2); } \ 00190 *s-- = c; \ 00191 } 00192 00205 int Fl_Tree::item_pathname(char *pathname, int pathnamelen, const Fl_Tree_Item *item) const { 00206 pathname[0] = '\0'; 00207 item = item ? item : _root; 00208 if ( !item ) return(-1); 00209 // Build pathname starting at end 00210 char *s = (pathname+pathnamelen-1); 00211 int slen = 0; // length of string compiled so far (including NULL) 00212 SAFE_RCAT('\0'); 00213 while ( item ) { 00214 if ( item->is_root() && showroot() == 0 ) break; // don't include root in path if showroot() off 00215 // Find name of current item 00216 const char *name = item->label() ? item->label() : "???"; // name for this item 00217 int len = strlen(name); 00218 // Add name to end of pathname[] 00219 for ( --len; len>=0; len-- ) { SAFE_RCAT(name[len]); } // rcat name of item 00220 SAFE_RCAT('/'); // rcat leading slash 00221 item = item->parent(); // move up tree (NULL==root) 00222 } 00223 if ( *(++s) == '/' ) ++s; // leave off leading slash from pathname 00224 if ( s != pathname ) memmove(pathname, s, slen); // Shift down right-aligned string 00225 return(0); 00226 } 00227 00229 void Fl_Tree::draw() { 00230 // Let group draw box+label but *NOT* children. 00231 // We handle drawing children ourselves by calling each item's draw() 00232 // 00233 // Handle group's bg 00234 Fl_Group::draw_box(); 00235 Fl_Group::draw_label(); 00236 // Handle tree 00237 if ( ! _root ) return; 00238 int cx = x() + Fl::box_dx(box()); 00239 int cy = y() + Fl::box_dy(box()); 00240 int cw = w() - Fl::box_dw(box()); 00241 int ch = h() - Fl::box_dh(box()); 00242 // These values are changed during drawing 00243 // 'Y' will be the lowest point on the tree 00244 int X = cx + _prefs.marginleft(); 00245 int Y = cy + _prefs.margintop() - (_vscroll->visible() ? _vscroll->value() : 0); 00246 int W = cw - _prefs.marginleft(); // - _prefs.marginright(); 00247 int Ysave = Y; 00248 fl_push_clip(cx,cy,cw,ch); 00249 { 00250 fl_font(_prefs.labelfont(), _prefs.labelsize()); 00251 _root->draw(X, Y, W, this, 00252 (Fl::focus()==this)?_item_focus:0, // show focus item ONLY if Fl_Tree has focus 00253 _prefs); 00254 } 00255 fl_pop_clip(); 00256 00257 // Show vertical scrollbar? 00258 int ydiff = (Y+_prefs.margintop())-Ysave; // ydiff=size of tree 00259 int ytoofar = (cy+ch) - Y; // ytoofar -- scrolled beyond bottom (eg. stow) 00260 00261 //printf("ydiff=%d ch=%d Ysave=%d ytoofar=%d value=%d\n", 00262 //int(ydiff),int(ch),int(Ysave),int(ytoofar), int(_vscroll->value())); 00263 00264 if ( ytoofar > 0 ) ydiff += ytoofar; 00265 if ( Ysave<cy || ydiff > ch || int(_vscroll->value()) > 1 ) { 00266 _vscroll->visible(); 00267 00268 int scrollsize = _scrollbar_size ? _scrollbar_size : Fl::scrollbar_size(); 00269 int sx = x()+w()-Fl::box_dx(box())-scrollsize; 00270 int sy = y()+Fl::box_dy(box()); 00271 int sw = scrollsize; 00272 int sh = h()-Fl::box_dh(box()); 00273 _vscroll->show(); 00274 _vscroll->range(0.0,ydiff-ch); 00275 _vscroll->resize(sx,sy,sw,sh); 00276 _vscroll->slider_size(float(ch)/float(ydiff)); 00277 } else { 00278 _vscroll->Fl_Slider::value(0); 00279 _vscroll->hide(); 00280 } 00281 fl_push_clip(cx,cy,cw,ch); 00282 Fl_Group::draw_children(); // draws any FLTK children set via Fl_Tree::widget() 00283 fl_pop_clip(); 00284 } 00285 00294 Fl_Tree_Item *Fl_Tree::next_visible_item(Fl_Tree_Item *item, int dir) { 00295 if ( ! item ) { // no start item? 00296 item = ( dir == FL_Up ) ? last() : first(); // start at top or bottom 00297 if ( ! item ) return(0); 00298 if ( item->visible_r() ) return(item); // return first/last visible item 00299 } 00300 switch ( dir ) { 00301 case FL_Up: return(item->prev_displayed(_prefs)); 00302 case FL_Down: return(item->next_displayed(_prefs)); 00303 default: return(item->next_displayed(_prefs)); 00304 } 00305 } 00306 00312 void Fl_Tree::set_item_focus(Fl_Tree_Item *item) { 00313 if ( _item_focus != item ) { // changed? 00314 _item_focus = item; // update 00315 if ( visible_focus() ) redraw(); // redraw to update focus box 00316 } 00317 } 00318 00331 const Fl_Tree_Item* Fl_Tree::find_clicked() const { 00332 if ( ! _root ) return(0); 00333 return(_root->find_clicked(_prefs)); 00334 } 00335 00342 void Fl_Tree::item_clicked(Fl_Tree_Item* val) { 00343 _callback_item = val; 00344 } 00345 00358 Fl_Tree_Item* Fl_Tree::first() { 00359 return(_root); // first item always root 00360 } 00361 00377 Fl_Tree_Item *Fl_Tree::next(Fl_Tree_Item *item) { 00378 if ( ! item ) return(0); 00379 return(item->next()); 00380 } 00381 00398 Fl_Tree_Item *Fl_Tree::prev(Fl_Tree_Item *item) { 00399 if ( ! item ) return(0); 00400 return(item->prev()); 00401 } 00402 00417 Fl_Tree_Item* Fl_Tree::last() { 00418 if ( ! _root ) return(0); 00419 Fl_Tree_Item *item = _root; 00420 while ( item->has_children() ) { 00421 item = item->child(item->children()-1); 00422 } 00423 return(item); 00424 } 00425 00438 Fl_Tree_Item *Fl_Tree::first_selected_item() { 00439 return(next_selected_item(0)); 00440 } 00441 00456 Fl_Tree_Item *Fl_Tree::next_selected_item(Fl_Tree_Item *item) { 00457 if ( ! item ) { 00458 if ( ! (item = first()) ) return(0); 00459 if ( item->is_selected() ) return(item); 00460 } 00461 while ( (item = item->next()) ) 00462 if ( item->is_selected() ) 00463 return(item); 00464 return(0); 00465 } 00466 00468 int Fl_Tree::handle(int e) { 00469 int ret = 0; 00470 // Developer note: Fl_Browser_::handle() used for reference here.. 00471 // #include <FL/names.h> // for event debugging 00472 // fprintf(stderr, "DEBUG: %s (%d)\n", fl_eventnames[e], e); 00473 if (e == FL_ENTER || e == FL_LEAVE) return(1); 00474 switch (e) { 00475 case FL_FOCUS: { 00476 // FLTK tests if we want focus. 00477 // If a nav key was used to give us focus, and we've got no saved 00478 // focus widget, determine which item gets focus depending on nav key. 00479 // 00480 if ( ! _item_focus ) { // no focus established yet? 00481 switch (Fl::event_key()) { // determine if focus was navigated.. 00482 case FL_Tab: { // received focus via TAB? 00483 if ( Fl::event_state(FL_SHIFT) ) { // SHIFT-TAB similar to FL_Up 00484 set_item_focus(next_visible_item(0, FL_Up)); 00485 } else { // TAB similar to FL_Down 00486 set_item_focus(next_visible_item(0, FL_Down)); 00487 } 00488 break; 00489 } 00490 case FL_Left: // received focus via LEFT or UP? 00491 case FL_Up: { // XK_ISO_Left_Tab 00492 set_item_focus(next_visible_item(0, FL_Up)); 00493 break; 00494 } 00495 case FL_Right: // received focus via RIGHT or DOWN? 00496 case FL_Down: 00497 default: { 00498 set_item_focus(next_visible_item(0, FL_Down)); 00499 break; 00500 } 00501 } 00502 } 00503 if ( visible_focus() ) redraw(); // draw focus change 00504 return(1); 00505 } 00506 case FL_UNFOCUS: { // FLTK telling us some other widget took focus. 00507 if ( visible_focus() ) redraw(); // draw focus change 00508 return(1); 00509 } 00510 case FL_KEYBOARD: { // keyboard shortcut 00511 // Do shortcuts first or scrollbar will get them... 00512 if (_prefs.selectmode() > FL_TREE_SELECT_NONE ) { 00513 if ( !_item_focus ) { 00514 set_item_focus(first()); 00515 } 00516 if ( _item_focus ) { 00517 int ekey = Fl::event_key(); 00518 switch (ekey) { 00519 case FL_Enter: // ENTER: selects current item only 00520 case FL_KP_Enter: 00521 if ( when() & ~FL_WHEN_ENTER_KEY) { 00522 select_only(_item_focus); 00523 show_item(_item_focus); // STR #2426 00524 return(1); 00525 } 00526 break; 00527 case ' ': // toggle selection state 00528 switch ( _prefs.selectmode() ) { 00529 case FL_TREE_SELECT_NONE: 00530 break; 00531 case FL_TREE_SELECT_SINGLE: 00532 if ( ! _item_focus->is_selected() ) // not selected? 00533 select_only(_item_focus); // select only this 00534 else 00535 deselect_all(); // select nothing 00536 break; 00537 case FL_TREE_SELECT_MULTI: 00538 select_toggle(_item_focus); 00539 break; 00540 } 00541 break; 00542 case FL_Right: // open children (if any) 00543 case FL_Left: { // close children (if any) 00544 if ( _item_focus ) { 00545 if ( ekey == FL_Right && _item_focus->is_close() ) { 00546 // Open closed item 00547 open(_item_focus); 00548 redraw(); 00549 ret = 1; 00550 } else if ( ekey == FL_Left && _item_focus->is_open() ) { 00551 // Close open item 00552 close(_item_focus); 00553 redraw(); 00554 ret = 1; 00555 } 00556 return(1); 00557 } 00558 break; 00559 } 00560 case FL_Up: // next item up 00561 case FL_Down: { // next item down 00562 set_item_focus(next_visible_item(_item_focus, ekey)); // next item up|dn 00563 if ( _item_focus ) { // item in focus? 00564 // Autoscroll 00565 int itemtop = _item_focus->y(); 00566 int itembot = _item_focus->y()+_item_focus->h(); 00567 if ( itemtop < y() ) { show_item_top(_item_focus); } 00568 if ( itembot > y()+h() ) { show_item_bottom(_item_focus); } 00569 // Extend selection 00570 if ( _prefs.selectmode() == FL_TREE_SELECT_MULTI && // multiselect on? 00571 (Fl::event_state() & FL_SHIFT) && // shift key? 00572 ! _item_focus->is_selected() ) { // not already selected? 00573 select(_item_focus); // extend selection.. 00574 } 00575 return(1); 00576 } 00577 break; 00578 } 00579 } 00580 } 00581 } 00582 break; 00583 } 00584 } 00585 00586 // Let Fl_Group take a shot at handling the event 00587 if (Fl_Group::handle(e)) { 00588 return(1); // handled? don't continue below 00589 } 00590 00591 // Handle events the child FLTK widgets didn't need 00592 00593 static Fl_Tree_Item *lastselect = 0; 00594 // fprintf(stderr, "ERCODEBUG: Fl_Tree::handle(): Event was %s (%d)\n", fl_eventnames[e], e); // DEBUGGING 00595 if ( ! _root ) return(ret); 00596 switch ( e ) { 00597 case FL_PUSH: { // clicked on a tree item? 00598 if (Fl::visible_focus() && handle(FL_FOCUS)) { 00599 Fl::focus(this); 00600 } 00601 lastselect = 0; 00602 Fl_Tree_Item *o = _root->find_clicked(_prefs); 00603 if ( ! o ) break; 00604 set_item_focus(o); // becomes new focus widget 00605 redraw(); 00606 ret |= 1; // handled 00607 if ( Fl::event_button() == FL_LEFT_MOUSE ) { 00608 if ( o->event_on_collapse_icon(_prefs) ) { // collapse icon clicked? 00609 open_toggle(o); 00610 } else if ( o->event_on_label(_prefs) && // label clicked? 00611 (!o->widget() || !Fl::event_inside(o->widget())) && // not inside widget 00612 (!_vscroll->visible() || !Fl::event_inside(_vscroll)) ) { // not on scroller 00613 switch ( _prefs.selectmode() ) { 00614 case FL_TREE_SELECT_NONE: 00615 break; 00616 case FL_TREE_SELECT_SINGLE: 00617 select_only(o); 00618 break; 00619 case FL_TREE_SELECT_MULTI: { 00620 if ( Fl::event_state() & FL_SHIFT ) { // SHIFT+PUSH? 00621 select(o); // add to selection 00622 } else if ( Fl::event_state() & FL_CTRL ) { // CTRL+PUSH? 00623 select_toggle(o); // toggle selection state 00624 lastselect = o; // save toggled item (prevent oscillation) 00625 } else { 00626 select_only(o); 00627 } 00628 break; 00629 } 00630 } 00631 } 00632 } 00633 break; 00634 } 00635 case FL_DRAG: { 00636 // do the scrolling first: 00637 int my = Fl::event_y(); 00638 if ( my < y() ) { // above top? 00639 int p = vposition()-(y()-my); 00640 if ( p < 0 ) p = 0; 00641 vposition(p); 00642 } else if ( my > (y()+h()) ) { // below bottom? 00643 int p = vposition()+(my-y()-h()); 00644 if ( p > (int)_vscroll->maximum() ) p = (int)_vscroll->maximum(); 00645 vposition(p); 00646 } 00647 if ( Fl::event_button() != FL_LEFT_MOUSE ) break; 00648 Fl_Tree_Item *o = _root->find_clicked(_prefs); 00649 if ( ! o ) break; 00650 set_item_focus(o); // becomes new focus widget 00651 redraw(); 00652 ret |= 1; 00653 // Item's label clicked? 00654 if ( o->event_on_label(_prefs) && 00655 (!o->widget() || !Fl::event_inside(o->widget())) && 00656 (!_vscroll->visible() || !Fl::event_inside(_vscroll)) ) { 00657 // Handle selection behavior 00658 switch ( _prefs.selectmode() ) { 00659 case FL_TREE_SELECT_NONE: break; // no selection changes 00660 case FL_TREE_SELECT_SINGLE: 00661 select_only(o); 00662 break; 00663 case FL_TREE_SELECT_MULTI: 00664 if ( Fl::event_state() & FL_CTRL && // CTRL-DRAG: toggle? 00665 lastselect != o ) { // not already toggled from last microdrag? 00666 select_toggle(o); // toggle selection 00667 lastselect = o; // save we toggled it (prevents oscillation) 00668 } else { 00669 select(o); // select this 00670 } 00671 break; 00672 } 00673 } 00674 break; 00675 } 00676 } 00677 return(ret); 00678 } 00679 00696 int Fl_Tree::deselect_all(Fl_Tree_Item *item, int docallback) { 00697 item = item ? item : first(); // NULL? use first() 00698 if ( ! item ) return(0); 00699 int count = 0; 00700 for ( ; item; item = next(item) ) { 00701 if ( item->is_selected() ) 00702 if ( deselect(item, docallback) ) 00703 ++count; 00704 } 00705 return(count); 00706 } 00707 00725 int Fl_Tree::select_all(Fl_Tree_Item *item, int docallback) { 00726 item = item ? item : first(); // NULL? use first() 00727 if ( ! item ) return(0); 00728 int count = 0; 00729 for ( ; item; item = next(item) ) { 00730 if ( !item->is_selected() ) 00731 if ( select(item, docallback) ) 00732 ++count; 00733 } 00734 return(count); 00735 } 00736 00754 int Fl_Tree::select_only(Fl_Tree_Item *selitem, int docallback) { 00755 selitem = selitem ? selitem : first(); // NULL? use first() 00756 if ( ! selitem ) return(0); 00757 int changed = 0; 00758 for ( Fl_Tree_Item *item = first(); item; item = item->next() ) { 00759 if ( item == selitem ) { 00760 if ( item->is_selected() ) continue; // don't count if already selected 00761 select(item, docallback); 00762 ++changed; 00763 } else { 00764 if ( item->is_selected() ) { 00765 deselect(item, docallback); 00766 ++changed; 00767 } 00768 } 00769 } 00770 return(changed); 00771 } 00772 00784 void Fl_Tree::show_item(Fl_Tree_Item *item, int yoff) { 00785 if ( ! item ) return; 00786 int newval = item->y() - y() - yoff + (int)_vscroll->value(); 00787 if ( newval < _vscroll->minimum() ) newval = (int)_vscroll->minimum(); 00788 if ( newval > _vscroll->maximum() ) newval = (int)_vscroll->maximum(); 00789 _vscroll->value(newval); 00790 redraw(); 00791 } 00792 00799 int Fl_Tree::displayed(Fl_Tree_Item *item) { 00800 return( (item->y() >= y() && item->y() <= (y()+h()-item->h())) ? 1 : 0); 00801 } 00802 00809 void Fl_Tree::show_item(Fl_Tree_Item *item) { 00810 if ( displayed(item) ) return; 00811 show_item_top(item); 00812 } 00813 00815 void Fl_Tree::show_item_top(Fl_Tree_Item *item) { 00816 item = item ? item : first(); 00817 if ( ! item ) return; 00818 show_item(item, 0); 00819 } 00820 00822 void Fl_Tree::show_item_middle(Fl_Tree_Item *item) { 00823 item = item ? item : first(); 00824 if ( ! item ) return; 00825 show_item(item, h()/2 - item->h()/2); 00826 } 00827 00829 void Fl_Tree::show_item_bottom(Fl_Tree_Item *item) { 00830 item = item ? item : first(); 00831 if ( ! item ) return; 00832 show_item(item, h() - item->h()); 00833 } 00834 00841 int Fl_Tree::vposition() const { 00842 return((int)_vscroll->value()); 00843 } 00844 00851 void Fl_Tree::vposition(int pos) { 00852 if (pos < 0) pos = 0; 00853 if (pos > _vscroll->maximum()) pos = (int)_vscroll->maximum(); 00854 if (pos == _vscroll->value()) return; 00855 _vscroll->value(pos); 00856 redraw(); 00857 } 00858 00862 void Fl_Tree::display(Fl_Tree_Item *item) { 00863 if ( ! item ) return; 00864 show_item_middle(item); 00865 } 00866 00873 void Fl_Tree::load(Fl_Preferences &prefs) 00874 { 00875 int i, j, n, pn = strlen(prefs.path()); 00876 char *p; 00877 const char *path = prefs.path(); 00878 if (strcmp(path, ".")==0) 00879 path += 1; // root path is empty 00880 else 00881 path += 2; // child path starts with "./" 00882 n = prefs.groups(); 00883 for (i=0; i<n; i++) { 00884 Fl_Preferences prefsChild(prefs, i); 00885 add(prefsChild.path()+2); // children always start with "./" 00886 load(prefsChild); 00887 } 00888 n = prefs.entries(); 00889 for (i=0; i<n; i++) { 00890 // We must remove all fwd slashes in the key and value strings. Replace with backslash. 00891 char *key = strdup(prefs.entry(i)); 00892 int kn = strlen(key); 00893 for (j=0; j<kn; j++) { 00894 if (key[j]=='/') key[j]='\\'; 00895 } 00896 char *val; prefs.get(key, val, ""); 00897 int vn = strlen(val); 00898 for (j=0; j<vn; j++) { 00899 if (val[j]=='/') val[j]='\\'; 00900 } 00901 if (vn<40) { 00902 int sze = pn + strlen(key) + vn; 00903 p = (char*)malloc(sze+5); 00904 sprintf(p, "%s/%s = %s", path, key, val); 00905 } else { 00906 int sze = pn + strlen(key) + 40; 00907 p = (char*)malloc(sze+5); 00908 sprintf(p, "%s/%s = %.40s...", path, key, val); 00909 } 00910 add(p[0]=='/'?p+1:p); 00911 free(p); 00912 free(val); 00913 free(key); 00914 } 00915 } 00916 00917 // 00918 // End of "$Id: Fl_Tree.cxx 7903 2010-11-28 21:06:39Z matt $". 00919 //