Author: greg.ercolano
Date: 2011-05-03 19:59:50 -0700 (Tue, 03 May 2011)
New Revision: 8632
Log:
Fl_Tree mods for handling escaped item menu names.
Docs clarified.
Also, tree-simple example's callback handler brought up to date.



Modified:
   branches/branch-1.3/FL/Fl_Tree.H
   branches/branch-1.3/examples/tree-simple.cxx
   branches/branch-1.3/src/Fl_Tree.cxx

Modified: branches/branch-1.3/FL/Fl_Tree.H
===================================================================
--- branches/branch-1.3/FL/Fl_Tree.H    2011-05-01 20:02:47 UTC (rev 8631)
+++ branches/branch-1.3/FL/Fl_Tree.H    2011-05-04 02:59:50 UTC (rev 8632)
@@ -115,8 +115,27 @@
 ///
 ///     The tree's callback() will be invoked when items change state or are 
open/closed.
 ///     when() controls when mouse/keyboard events invoke the callback.
-///     callback_item() and callback_reason() can be used to determine the 
cause of the callback.
+///     callback_item() and callback_reason() can be used to determine the 
cause of the callback. eg:
 ///
+/// \code
+/// void MyTreeCallback(Fl_Widget *w, void *data) {
+///   Fl_Tree      *tree = (Fl_Tree*)w;
+///   Fl_Tree_Item *item = (Fl_Tree_Item*)tree->callback_item();       // get 
selected item
+///   switch ( tree->callback_reason() ) {
+///     case FL_TREE_REASON_SELECTED: [..]
+///     case FL_TREE_REASON_DESELECTED: [..]
+///     case FL_TREE_REASON_OPENED: [..]
+///     case FL_TREE_REASON_CLOSED: [..]
+///   }
+/// \endcode
+///
+///     To get the item's full menu pathname, you can use 
Fl_Tree_Item::item_pathname(), eg:
+///
+/// \code
+///   char pathname[256] = "???";
+///   tree->item_pathname(pathname, sizeof(pathname), item);           // eg. 
"Parent/Child/Item"
+/// \endcode
+///
 ///     To walk all the items of the tree from top to bottom:
 /// \code
 /// // Walk all the items in the tree, and print their labels
@@ -328,10 +347,13 @@
   /// Handles redrawing if anything was actually changed.
   /// Invokes the callback depending on the value of optional parameter \p 
docallback.
   ///
+  /// Items or submenus that themselves contain slashes ('/' or '\')
+  /// should be escaped, e.g. open("Holidays/12\\/25\//2010").
+  ///
   /// The callback can use callback_item() and callback_reason() respectively 
to determine 
   /// the item changed and the reason the callback was called.
   ///
-  /// \param[in] path -- the tree item's pathname (eg. "Flintstones/Fred")
+  /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
   /// \param[in] docallback -- A flag that determines if the callback() is 
invoked or not:
   ///     -   0 - callback() is not invoked
   ///     -   1 - callback() is invoked if item changed,
@@ -401,10 +423,13 @@
   /// Handles redrawing if anything was actually changed.
   /// Invokes the callback depending on the value of optional parameter \p 
docallback.
   ///
+  /// Items or submenus that themselves contain slashes ('/' or '\')
+  /// should be escaped, e.g. close("Holidays/12\\/25\//2010").
+  ///
   /// The callback can use callback_item() and callback_reason() respectively 
to determine 
   /// the item changed and the reason the callback was called.
   ///
-  /// \param[in] path -- the tree item's pathname (eg. "Flintstones/Fred")
+  /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
   /// \param[in] docallback -- A flag that determines if the callback() is 
invoked or not:
   ///     -   0 - callback() is not invoked
   ///     -   1 - callback() is invoked if item changed,
@@ -436,10 +461,13 @@
   }
   /// See if item specified by \p path (eg: "Parent/child/item") is open.
   ///
+  /// Items or submenus that themselves contain slashes ('/' or '\')
+  /// should be escaped, e.g. is_open("Holidays/12\\/25\//2010").
+  ///
   /// Items that are 'open' are themselves not necessarily visible;
   /// one of the item's parents might be closed.
   ///
-  /// \param[in] path -- the tree item's pathname (eg. "Flintstones/Fred")
+  /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
   /// \returns
   ///     -    1 - OK: item is open
   ///     -    0 - OK: item is closed
@@ -462,7 +490,10 @@
   }
   /// See if item specified by \p path (eg: "Parent/child/item") is closed.
   ///
-  /// \param[in] path -- the tree item's pathname (eg. "Flintstones/Fred")
+  /// Items or submenus that themselves contain slashes ('/' or '\')
+  /// should be escaped, e.g. is_close("Holidays/12\\/25\//2010").
+  ///
+  /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
   /// \returns
   ///     -   1 - OK: item is closed
   ///     -   0 - OK: item is open
@@ -506,10 +537,13 @@
   /// Handles redrawing if anything was actually changed.
   /// Invokes the callback depending on the value of optional parameter \p 
docallback.
   ///
+  /// Items or submenus that themselves contain slashes ('/' or '\')
+  /// should be escaped, e.g. select("Holidays/12\\/25\//2010").
+  ///
   /// The callback can use callback_item() and callback_reason() respectively 
to determine 
   /// the item changed and the reason the callback was called.
   ///
-  /// \param[in] path -- the tree item's pathname (eg. "Flintstones/Fred")
+  /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
   /// \param[in] docallback -- A flag that determines if the callback() is 
invoked or not:
   ///     -   0 - the callback() is not invoked
   ///     -   1 - the callback() is invoked if item changed state,
@@ -578,10 +612,13 @@
   /// Handles redrawing if anything was actually changed.
   /// Invokes the callback depending on the value of optional parameter \p 
docallback.
   ///
+  /// Items or submenus that themselves contain slashes ('/' or '\')
+  /// should be escaped, e.g. deselect("Holidays/12\\/25\//2010").
+  ///
   /// The callback can use callback_item() and callback_reason() respectively 
to determine 
   /// the item changed and the reason the callback was called.
   ///
-  /// \param[in] path -- the tree item's pathname (eg. "Flintstones/Fred")
+  /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
   /// \param[in] docallback -- A flag that determines if the callback() is 
invoked or not:
   ///     -   0 - the callback() is not invoked
   ///     -   1 - the callback() is invoked if item changed state,
@@ -615,7 +652,10 @@
   }
   /// See if item specified by \p path (eg: "Parent/child/item") is selected.
   ///
-  /// \param[in] path -- the tree item's pathname (eg. "Flintstones/Fred")
+  /// Items or submenus that themselves contain slashes ('/' or '\')
+  /// should be escaped, e.g. is_selected("Holidays/12\\/25\//2010").
+  ///
+  /// \param[in] path -- the tree item's pathname (e.g. "Flintstones/Fred")
   /// \returns
   ///     -   1 : item selected
   ///     -   0 : item deselected

Modified: branches/branch-1.3/examples/tree-simple.cxx
===================================================================
--- branches/branch-1.3/examples/tree-simple.cxx        2011-05-01 20:02:47 UTC 
(rev 8631)
+++ branches/branch-1.3/examples/tree-simple.cxx        2011-05-04 02:59:50 UTC 
(rev 8632)
@@ -31,12 +31,30 @@
 #include <FL/Fl_Tree.H>
 
 // Tree's callback
-//    Invoked whenever someone clicks an item.
+//    Invoked whenever an item's state changes.
 //
 void TreeCallback(Fl_Widget *w, void *data) {
-  Fl_Tree      *tree = (Fl_Tree*)w;
-  Fl_Tree_Item *item = (Fl_Tree_Item*)tree->item_clicked();
-  fprintf(stderr, "TreeCallback: item clicked='%s'\n", 
(item)?item->label():"???");
+  Fl_Tree *tree = (Fl_Tree*)w;
+  Fl_Tree_Item *item = (Fl_Tree_Item*)tree->callback_item();
+  if ( ! item ) return;
+  switch ( tree->callback_reason() ) {
+    case FL_TREE_REASON_SELECTED: {
+      char pathname[256];
+      tree->item_pathname(pathname, sizeof(pathname), item);
+      fprintf(stderr, "TreeCallback: Item selected='%s', Full 
pathname='%s'\n", item->label(), pathname);
+      break;
+    }
+    case FL_TREE_REASON_DESELECTED:
+      // fprintf(stderr, "TreeCallback: Item '%s' deselected\n", 
item->label());
+      break;
+    case FL_TREE_REASON_OPENED:
+      // fprintf(stderr, "TreeCallback: Item '%s' opened\n", item->label());
+      break;
+    case FL_TREE_REASON_CLOSED:
+      // fprintf(stderr, "TreeCallback: Item '%s' closed\n", item->label());
+    default:
+      break;
+  }
 }
 
 int main(int argc, char *argv[]) {
@@ -57,9 +75,15 @@
     tree->add("Simpsons/Marge");
     tree->add("Simpsons/Bart");
     tree->add("Simpsons/Lisa");
+    tree->add("Holidays/01\\/01 New Years");
+    tree->add("Holidays/02\\/15 Valentine's Day");
+    tree->add("Holidays/05\\/05 Cinco de Mayo");
+    tree->add("Holidays/07\\/04 Independence Day");
+    tree->add("Holidays/12\\/25 Christmas");
 
-    // Start with one of the items closed
+    // Start with some items closed
     tree->close("Simpsons");
+    tree->close("Holidays");
   }
   win->end();
   win->resizable(win);

Modified: branches/branch-1.3/src/Fl_Tree.cxx
===================================================================
--- branches/branch-1.3/src/Fl_Tree.cxx 2011-05-01 20:02:47 UTC (rev 8631)
+++ branches/branch-1.3/src/Fl_Tree.cxx 2011-05-04 02:59:50 UTC (rev 8632)
@@ -38,6 +38,7 @@
 }
 
 // INTERNAL: Parse elements from path into an array of null terminated strings
+//    Handles escape characters.
 //    Path="/aa/bb"
 //    Return: arr[0]="aa", arr[1]="bb", arr[2]=0
 //    Caller must call free_path(arr).
@@ -48,19 +49,29 @@
   int seps = 1;                                // separator count (1: first 
item)
   int arrsize = 1;                     // array size (1: first item)
   char *save = strdup(path);           // make copy we can modify
-  char *s = save;
-  while ( ( s = strchr(s, '/') ) ) {
-    while ( *s == '/' ) { *s++ = 0; seps++; }
-    if ( *s ) { arrsize++; }
+  char *sin = save, *sout = save;
+  while ( *sin ) {
+    if ( *sin == '\\' ) {              // handle escape character
+      *sout++ = *++sin;
+      if ( *sin ) ++sin;
+    } else if ( *sin == '/' ) {                // handle submenu
+      *sout++ = 0;
+      sin++;
+      seps++;
+      arrsize++;
+    } else {                           // all other chars
+      *sout++ = *sin++;
+    }
   }
+  *sout = 0;
   arrsize++;                           // (room for terminating NULL) 
   // Second pass: create array, save nonblank elements
   char **arr = (char**)malloc(sizeof(char*) * arrsize);
   int t = 0;
-  s = save;
+  sin = save;
   while ( seps-- > 0 ) {
-    if ( *s ) { arr[t++] = s; }                // skips empty fields, eg. '//'
-    s += (strlen(s) + 1);
+    if ( *sin ) { arr[t++] = sin; }    // skips empty fields, e.g. '//'
+    sin += (strlen(sin) + 1);
   }
   arr[t] = 0;
   return(arr);
@@ -111,6 +122,15 @@
 /// Adds a new item, given a 'menu style' path, eg: "/Parent/Child/item".
 /// Any parent nodes that don't already exist are created automatically.
 /// Adds the item based on the value of sortorder().
+///
+/// To specify items or submenus that contain slashes ('/' or '\')
+/// use an escape character to protect them, e.g.
+///
+/// \code
+///     tree->add("/Holidays/Photos/12\\/25\\2010");          // Adds item 
"12/25/2010"
+///     tree->add("/Pathnames/c:\\\\Program Files\\\\MyApp"); // Adds item 
"c:\Program Files\MyApp"
+/// \endcode
+///
 /// \returns the child item created, or 0 on error.
 ///
 Fl_Tree_Item* Fl_Tree::add(const char *path) {
@@ -156,12 +176,19 @@
 }
 
 /// Find the item, given a menu style path, eg: "/Parent/Child/item".
-///
 /// There is both a const and non-const version of this method.
 /// Const version allows pure const methods to use this method 
 /// to do lookups without causing compiler errors.
 ///
-/// \param[in] path -- the tree item's pathname to be found (eg. 
"Flintstones/Fred")
+/// To specify items or submenus that contain slashes ('/' or '\')
+/// use an escape character to protect them, e.g.
+///
+/// \code
+///     tree->add("/Holidays/Photos/12\\/25\\2010");          // Adds item 
"12/25/2010"
+///     tree->add("/Pathnames/c:\\\\Program Files\\\\MyApp"); // Adds item 
"c:\Program Files\MyApp"
+/// \endcode
+///
+/// \param[in] path -- the tree item's pathname to be found (e.g. 
"Flintstones/Fred")
 /// \returns the item, or NULL if not found.
 ///
 /// \see item_pathname()
@@ -195,6 +222,9 @@
 /// Find the pathname for the specified \p item.
 /// If \p item is NULL, root() is used.
 /// The tree's root will be included in the pathname of showroot() is on.
+/// Menu items or submenus that contain slashes ('/' or '\') in their names
+/// will be escaped with a backslash. This is symmetrical with the add()
+/// function which uses the same escape pattern to set names.
 /// \param[in] pathname The string to use to return the pathname
 /// \param[in] pathnamelen The maximum length of the string (including NULL). 
Must not be zero.
 /// \param[in] item The item whose pathname is to be returned.
@@ -218,7 +248,12 @@
     const char *name = item->label() ? item->label() : "???";  // name for 
this item
     int len = strlen(name);
     // Add name to end of pathname[]
-    for ( --len; len>=0; len-- ) { SAFE_RCAT(name[len]); }     // rcat name of 
item
+    for ( --len; len>=0; len-- ) {
+      SAFE_RCAT(name[len]);                                    // rcat name of 
item
+      if ( name[len] == '/' || name[len] == '\\' ) {
+        SAFE_RCAT('\\');                                       // escape front 
or back slashes within name
+      }
+    }
     SAFE_RCAT('/');                                            // rcat leading 
slash
     item = item->parent();                                     // move up tree 
(NULL==root)
   }
@@ -258,7 +293,7 @@
   
   // Show vertical scrollbar?
   int ydiff = (Y+_prefs.margintop())-Ysave;            // ydiff=size of tree
-  int ytoofar = (cy+ch) - Y;                           // ytoofar -- scrolled 
beyond bottom (eg. stow)
+  int ytoofar = (cy+ch) - Y;                           // ytoofar -- scrolled 
beyond bottom (e.g. stow)
   
   //printf("ydiff=%d ch=%d Ysave=%d ytoofar=%d value=%d\n",
   //int(ydiff),int(ch),int(Ysave),int(ytoofar), int(_vscroll->value()));
@@ -813,7 +848,7 @@
 }
 
 /// Adjust the vertical scroll bar to show \p item at the top
-/// of the display IF it is currently off-screen (eg. show_item_top()).
+/// of the display IF it is currently off-screen (e.g. show_item_top()).
 /// If it is already on-screen, no change is made.
 ///
 /// \param[in] item The item to be shown. If NULL, first() is used.

_______________________________________________
fltk-commit mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-commit

Reply via email to