diff --git a/CHANGES b/CHANGES
index cc402681f35793b3d306f1fd301e78ba4db5be68..b91781f95adea4e3585b5e4fa3d6fa6c0a819835 100644
--- a/CHANGES
+++ b/CHANGES
@@ -157,6 +157,8 @@ CHANGES IN FLTK 1.3.0
 	- hide() and show() methods are now virtual from Fl_Widget,
 	  was only virtual since Fl_Window derived classes before.
 	  So now widget->hide() will work if widget is a window.
+        - New widgets: Fl_Tree, Fl_Table, Fl_Native_File_Chooser
+        - added Fl_Menu_ methods: insert(), find_index(), clear_submenu()
 
 CHANGES IN FLTK 1.1.9
 
diff --git a/FL/Fl_Menu_.H b/FL/Fl_Menu_.H
index 5daec157d7b10c8e01815aae2e221a3086db5dce..8f3b64449ee55eabfb413d1bd3943e633ae0c485 100644
--- a/FL/Fl_Menu_.H
+++ b/FL/Fl_Menu_.H
@@ -66,6 +66,9 @@ public:
   const Fl_Menu_Item* picked(const Fl_Menu_Item*);
   const Fl_Menu_Item* find_item(const char *name);
   const Fl_Menu_Item* find_item(Fl_Callback*);
+  int find_index(const char *name) const;
+  int find_index(const Fl_Menu_Item *item) const;
+  int find_index(Fl_Callback *cb) const;
 
   const Fl_Menu_Item* test_shortcut() {return picked(menu()->test_shortcut());}
   void global();
@@ -77,14 +80,21 @@ public:
   const Fl_Menu_Item *menu() const {return menu_;}
   void menu(const Fl_Menu_Item *m);
   void copy(const Fl_Menu_Item *m, void* user_data = 0);
+  int insert(int index, const char*, int shortcut, Fl_Callback*, void* = 0, int = 0);
   int  add(const char*, int shortcut, Fl_Callback*, void* = 0, int = 0);
-  /** See int Fl_Menu_::add(const char* label, int shortcut, Fl_Callback*, void *user_data=0, int flags=0)*/
+  /** See int Fl_Menu_::add(const char* label, int shortcut, Fl_Callback*, void *user_data=0, int flags=0) */
   int  add(const char* a, const char* b, Fl_Callback* c, void* d = 0, int e = 0) {
-      return add(a,fl_old_shortcut(b),c,d,e);}
+      return add(a,fl_old_shortcut(b),c,d,e);
+  }
+  /** See int Fl_Menu_::insert(const char* label, int shortcut, Fl_Callback*, void *user_data=0, int flags=0) */
+  int insert(int index, const char* a, const char* b, Fl_Callback* c, void* d = 0, int e = 0) {
+      return insert(index,a,fl_old_shortcut(b),c,d,e);
+  }
   int  add(const char *);
   int  size() const ;
   void size(int W, int H) { Fl_Widget::size(W, H); }
   void clear();
+  int clear_submenu(int index);
   void replace(int,const char *);
   void remove(int);
  /** Changes the shortcut of item i to n.  */
diff --git a/FL/Fl_Menu_Item.H b/FL/Fl_Menu_Item.H
index 0ea5c792fbdc555c9555d0e545d736bee98d5de6..31620e16fbac03ffb823c301b197e275f264744c 100644
--- a/FL/Fl_Menu_Item.H
+++ b/FL/Fl_Menu_Item.H
@@ -386,6 +386,7 @@ struct FL_EXPORT Fl_Menu_Item {
   /** back compatibility only \deprecated. */
   void uncheck() {flags &= ~FL_MENU_VALUE;}
 
+  int insert(int,const char*,int,Fl_Callback*,void* =0, int =0);
   int add(const char*, int shortcut, Fl_Callback*, void* =0, int = 0);
 
   /** See int add(const char*, int shortcut, Fl_Callback*, void*, int) */
diff --git a/src/Fl_Menu_.cxx b/src/Fl_Menu_.cxx
index ce417bfa9ea6d89bc40ef92321e79974ec754df2..2e3405885f3018228be7c9475ba251f9d0989783 100644
--- a/src/Fl_Menu_.cxx
+++ b/src/Fl_Menu_.cxx
@@ -100,11 +100,13 @@ int Fl_Menu_::item_pathname(char *name, int namelen, const Fl_Menu_Item *findite
 }
 
 /**
- Find menu item index, given a menu pathname such as "Edit/Copy".
+ Find the menu item for a given menu \p pathname, such as "Edit/Copy".
  
- This method finds a menu item in a menu array, also traversing submenus, but
+ This method finds a menu item in the menu array, also traversing submenus, but
  not submenu pointers.
 
+ To get the menu item's index, use find_index(const char*)
+
   \b Example:
   \code
     Fl_Menu_Bar *menubar = new Fl_Menu_Bar(..);
@@ -120,25 +122,84 @@ int Fl_Menu_::item_pathname(char *name, int namelen, const Fl_Menu_Item *findite
 	item->labelcolor(FL_GREEN);
     }
   \endcode
-  \returns The item found, or NULL if not found.
-  \see 
 
- \param name path and name of the menu item
- \return NULL if not found
- \see Fl_Menu_::find_item(Fl_Callback*), item_pathname() 
+  \param pathname The path and name of the menu item
+  \returns The item found, or NULL if not found
+  \see find_index(const char*), find_item(Fl_Callback*), item_pathname() 
 */
-const Fl_Menu_Item * Fl_Menu_::find_item(const char *name) {
-  char menupath[1024] = "";	// File/Export
+const Fl_Menu_Item * Fl_Menu_::find_item(const char *pathname) {
+  int i = find_index(pathname);
+  return( (i==-1) ? 0 : (const Fl_Menu_Item*)(menu_+i));
+}
 
+/**
+ Find the index the menu array for given \p item.
+ 
+ A way to convert a menu item pointer into an index.
+
+ Current implementation is fast and not expensive.
+
+ \code
+   // Convert an index-to-item
+   int index = 12;
+   const Fl_Menu_Item *item = mymenu->menu() + index;
+
+   // Convert an item-to-index
+   int index = mymenu->find_index(item);
+   if ( index == -1 ) { ..error.. }
+ \endcode
+
+ \param item The *item to be found
+ \returns    The index of the item, or -1 if not found.
+ \see        menu()
+*/
+int Fl_Menu_::find_index(const Fl_Menu_Item *item) const {
+  Fl_Menu_Item *max = menu_+size();
+  if (item<menu_ || item>=max) return(-1);
+  return(item-menu_);
+}
+
+/**
+ Find the index into the menu array for a given callback \p cb.
+ 
+ This method finds a menu item's index position, also traversing submenus, but
+ not submenu pointers. This is useful if an application uses internationalisation
+ and a menu item can not be found using its label. This search is also much faster.
+ 
+ \param cb Find the first item with this callback
+ \returns  The index of the item with the specific callback, or -1 if not found
+ \see      find_index(const char*)
+ */
+int Fl_Menu_::find_index(Fl_Callback *cb) const {
+  for ( int t=0; t < size(); t++ )
+    if (menu_[t].callback_==cb)
+      return(t);
+  return(-1);
+}
+
+/**
+ Find the menu item index for a given menu \p pathname, such as "Edit/Copy".
+ 
+ This method finds a menu item's index position for the given menu pathname,
+ also traversing submenus, but not submenu pointers.
+
+ To get the menu item pointer for a pathname, use find_item()
+
+ \param pathname The path and name of the menu item index to find
+ \returns        The index of the matching item, or -1 if not found.
+ \see            item_pathname()
+
+*/
+int Fl_Menu_::find_index(const char *pathname) const {
+  char menupath[1024] = "";	// File/Export
   for ( int t=0; t < size(); t++ ) {
     Fl_Menu_Item *m = menu_ + t;
-
     if (m->flags&FL_SUBMENU) {
       // IT'S A SUBMENU
       // we do not support searches through FL_SUBMENU_POINTER links
       if (menupath[0]) strlcat(menupath, "/", sizeof(menupath));
       strlcat(menupath, m->label(), sizeof(menupath));
-      if (!strcmp(menupath, name)) return m;
+      if (!strcmp(menupath, pathname)) return(t);
     } else {
       if (!m->label()) {
 	// END OF SUBMENU? Pop back one level.
@@ -147,21 +208,19 @@ const Fl_Menu_Item * Fl_Menu_::find_item(const char *name) {
 	else menupath[0] = '\0';
 	continue;
       }
-
       // IT'S A MENU ITEM
       char itempath[1024];	// eg. Edit/Copy
       strcpy(itempath, menupath);
       if (itempath[0]) strlcat(itempath, "/", sizeof(itempath));
       strlcat(itempath, m->label(), sizeof(itempath));
-      if (!strcmp(itempath, name)) return m;
+      if (!strcmp(itempath, pathname)) return(t);
     }
   }
-
-  return (const Fl_Menu_Item *)0;
+  return(-1);
 }
 
 /**
- Find menu item index given a callback.
+ Find the menu item for the given callback \p cb.
  
  This method finds a menu item in a menu array, also traversing submenus, but
  not submenu pointers. This is useful if an application uses 
@@ -169,8 +228,8 @@ const Fl_Menu_Item * Fl_Menu_::find_item(const char *name) {
  search is also much faster.
  
  \param cb find the first item with this callback
- \return NULL if not found
- \see Fl_Menu_::find_item(const char*)
+ \returns The item found, or NULL if not found
+ \see find_item(const char*)
  */
 const Fl_Menu_Item * Fl_Menu_::find_item(Fl_Callback *cb) {
   for ( int t=0; t < size(); t++ ) {
@@ -286,7 +345,7 @@ void Fl_Menu_::menu(const Fl_Menu_Item* m) {
 
 /** 
   Sets the menu array pointer with a copy of m that will be automatically deleted. 
-  If ud is not NULL, then all user data pointers are changed in the menus as well.
+  If userdata \p ud is not NULL, then all user data pointers are changed in the menus as well.
   See void Fl_Menu_::menu(const Fl_Menu_Item* m). 
 */
 void Fl_Menu_::copy(const Fl_Menu_Item* m, void* ud) {
@@ -330,6 +389,47 @@ void Fl_Menu_::clear() {
   }
 }
 
+/**
+ Clears the specified submenu pointed to by \p index of all menu items.
+
+ This method is useful for clearing a submenu so that it can be
+ re-populated with new items. Example: a "File/Recent Files/..." submenu
+ that shows the last few files that have been opened.
+
+ The specified \p index must point to a submenu.
+ 
+ The submenu is cleared with remove().
+ If the menu array was directly set with menu(x), then copy() 
+ is done to make a private array.
+
+ \warning Since this method can change the internal menu array, any menu
+ item pointers or indecies the application may have cached can become
+ stale, and should be recalculated/refreshed.
+
+ \b Example:
+ \code
+   int index = menubar->find_index("File/Recent");    // get index of "File/Recent" submenu
+   if ( index != -1 ) menubar->clear_submenu(index);  // clear the submenu
+   menubar->add("File/Recent/Aaa");
+   menubar->add("File/Recent/Bbb");
+   [..]
+ \endcode
+
+ \param index The index of the submenu to be cleared
+ \returns 0 on success, -1 if the index is out of range or not a submenu
+ \see remove(int)
+ */
+int Fl_Menu_::clear_submenu(int index) {
+  if ( index < 0 || index >= size() ) return(-1);
+  if ( ! (menu_[index].flags & FL_SUBMENU) ) return(-1);
+  ++index;					// advance to first item in submenu
+  while ( index < size() ) {                    // keep remove()ing top item until end is reached
+    if ( menu_[index].text == 0 ) break;	// end of this submenu? done
+    remove(index);				// remove items/submenus
+  }
+  return(0);
+}
+
 //
 // End of "$Id$".
 //
diff --git a/src/Fl_Menu_add.cxx b/src/Fl_Menu_add.cxx
index 96f4a443c11c3ea241dd06fdaeb010dee42fa829..036fc2d0de6f5265cf00489051751ceaccfcca74 100644
--- a/src/Fl_Menu_add.cxx
+++ b/src/Fl_Menu_add.cxx
@@ -53,11 +53,12 @@ extern Fl_Menu_* fl_menu_array_owner; // in Fl_Menu_.cxx
 
 // Insert a single Fl_Menu_Item into an array of size at offset n,
 // if this is local_array it will be reallocated if needed.
-static Fl_Menu_Item* insert(
-  Fl_Menu_Item* array, int size,
-  int n,
-  const char *text,
-  int flags
+static Fl_Menu_Item* array_insert(
+  Fl_Menu_Item* array,  // array to modify
+  int size,             // size of array
+  int n,                // index of new insert position
+  const char *text,     // text of new item (copy is made)
+  int flags             // flags for new item
 ) {
   if (array == local_array && size >= local_array_alloc) {
     local_array_alloc = 2*size;
@@ -106,6 +107,27 @@ int Fl_Menu_Item::add(
   Fl_Callback *cb,	
   void *data,
   int myflags
+) {
+  return(insert(-1,mytext,sc,cb,data,myflags));		// -1: append
+}
+
+/** Inserts an item at position \p index.
+    
+    If \p index is -1, the item is added the same way as Fl_Menu_Item::add().
+
+    If 'mytext' contains any un-escaped front slashes (/), it's assumed 
+    a menu pathname is being specified, and the value of \p index 
+    will be ignored.
+
+    In all other aspects, the behavior of insert() is the same as add().
+*/
+int Fl_Menu_Item::insert(
+  int index,
+  const char *mytext,
+  int sc,
+  Fl_Callback *cb,	
+  void *data,
+  int myflags
 ) {
   Fl_Menu_Item *array = this;
   Fl_Menu_Item *m = this;
@@ -133,17 +155,18 @@ int Fl_Menu_Item::add(
 
     item = buf;
     if (*p != '/') break; /* not a menu title */
-    mytext = p+1;	/* point at item title */
+    index = -1;           /* any submenu specified overrides insert position */
+    mytext = p+1;         /* point at item title */
 
     /* find a matching menu title: */
     for (; m->text; m = m->next())
       if (m->flags&FL_SUBMENU && !compare(item, m->text)) break;
 
     if (!m->text) { /* create a new menu */
-      int n = m-array;
-      array = insert(array, msize, n, item, FL_SUBMENU|flags1);
+      int n = (index==-1) ? m-array : index;
+      array = array_insert(array, msize, n, item, FL_SUBMENU|flags1);
       msize++;
-      array = insert(array, msize, n+1, 0, 0);
+      array = array_insert(array, msize, n+1, 0, 0);
       msize++;
       m = array+n;
     }
@@ -156,11 +179,11 @@ int Fl_Menu_Item::add(
     if (!(m->flags&FL_SUBMENU) && !compare(m->text,item)) break;
 
   if (!m->text) {	/* add a new menu item */
-    int n = m-array;
-    array = insert(array, msize, n, item, myflags|flags1);
+    int n = (index==-1) ? m-array : index;
+    array = array_insert(array, msize, n, item, myflags|flags1);
     msize++;
     if (myflags & FL_SUBMENU) { // add submenu delimiter
-      array = insert(array, msize, n+1, 0, 0);
+      array = array_insert(array, msize, n+1, 0, 0);
       msize++;
     }
     m = array+n;
@@ -179,17 +202,21 @@ int Fl_Menu_Item::add(
 /**
   Adds a new menu item.
   
-  \param[in] label The text label for the menu item.
+  \param[in] label    The text label for the menu item.
   \param[in] shortcut Optional keyboard shortcut that can be an int or string; (FL_CTRL+'a') or "^a". Default 0 if none.
   \param[in] callback Optional callback invoked when user clicks the item. Default 0 if none.
   \param[in] userdata Optional user data passed as an argument to the callback. Default 0 if none.
-  \param[in] flags Optional flags that control the type of menu item; see below. Default is 0 for none.
-  \returns The index into the menu() array, where the entry was added.
+  \param[in] flags    Optional flags that control the type of menu item; see below. Default is 0 for none.
+  \returns            The index into the menu() array, where the entry was added.
   
   \par Description
   If the menu array was directly set with menu(x), then copy() is done 
   to make a private array.
   \par 
+  Since this method can change the internal menu array, any menu item
+  pointers or indecies the application may have cached can become stale,
+  and should be recalculated/refreshed.
+  \par
   A menu item's callback must not add() items to its parent menu during the callback.
 
   <B>Detailed Description of Parameters</B>
@@ -219,23 +246,32 @@ int Fl_Menu_Item::add(
   \par 
   This parameter is optional, and defaults to 0 to indicate no shortcut.
   \par
-  Shortcut can be 0L, or either a modifier/key combination (for example
-  FL_CTRL+'A') or a string describing the shortcut in one of two ways:
+  The shortcut can either be a raw integer value (eg. FL_CTRL+'A')
+  or a string (eg. "^c" or "^97").
+  \par
+  Raw integer shortcuts can be a combination of keyboard chars (eg. 'A')
+  and optional keyboard modifiers (see Fl::event_state(), e.g. FL_SHIFT, etc).
+  \par
+  String shortcuts can be specified in one of two ways:
+  \par
   \verbatim
    [#+^]<ascii_value>    e.g. "97", "^97", "+97", "#97"
    [#+^]<ascii_char>     e.g. "a", "^a", "+a", "#a"
   \endverbatim
+  \par
   ..where \<ascii_value\> is a decimal value representing an
-  ascii character (eg. 97 is the ascii for 'a'), and the optional
+  ascii character (eg. 97 is the ascii code for 'a'), and the optional
   prefixes enhance the value that follows. Multiple prefixes must
   appear in the above order.
+  \par
   \verbatim
    # - Alt
    + - Shift
    ^ - Control
   \endverbatim
-  Text shortcuts are converted to integer shortcut by calling 
-  unsigned int fl_old_shortcut(const char*).
+  \par
+  Internally, the text shortcuts are converted to integer values using
+  fl_old_shortcut(const char*).
 
   \par callback
   The callback to invoke when this menu item is selected. 
@@ -264,8 +300,48 @@ int Fl_Menu_Item::add(
       FL_MENU_DIVIDER      // Creates divider line below this item. Also ends a group of radio buttons.
   \endcode
 
+  \todo Raw integer shortcut needs examples. 
+        Dependent on responses to http://fltk.org/newsgroups.php?gfltk.development+v:10086 and results of STR#2344
  */
 int Fl_Menu_::add(const char *label,int shortcut,Fl_Callback *callback,void *userdata,int flags) {
+  return(insert(-1,label,shortcut,callback,userdata,flags));	// -1: append
+}
+
+/**
+  Inserts a new menu item at the specified \p index position.
+
+  If \p index is -1, the menu item is appended; same behavior as add().
+
+  The value of \p index will be ignored if \p label contains un-escaped 
+  front-slashes (/) indicating a menu pathname as the point of insertion.
+  A menu pathname will override the value of \p index.
+  
+  For more details, see add(). Except for the \p index parameter, add()
+  has more detailed information on parameters and behavior, and is
+  functionally equivalent,
+
+  \param[in] index    The menu array's index position where the new item
+                      is inserted. If -1, behavior is the same as add().
+  \param[in] label    The text label for the menu item.
+  \param[in] shortcut Optional keyboard shortcut. Can be an int (FL_CTRL+'a')
+                      or a string ("^a"). Default is 0.
+  \param[in] callback Optional callback invoked when user clicks the item.
+                      Default 0 if none.
+  \param[in] userdata Optional user data passed as an argument to the callback.
+                      Default 0 if none.
+  \param[in] flags    Optional flags that control the type of menu item; 
+                      see add() for more info. Default is 0 for none.
+  \returns            The index into the menu() array, where the entry was added.
+
+ */
+int Fl_Menu_::insert(
+  int index,
+  const char *label,
+  int shortcut,
+  Fl_Callback *callback,
+  void *userdata,
+  int flags
+) {
   // make this widget own the local array:
   if (this != fl_menu_array_owner) {
     if (fl_menu_array_owner) {
@@ -299,7 +375,7 @@ int Fl_Menu_::add(const char *label,int shortcut,Fl_Callback *callback,void *use
     }
     fl_menu_array_owner = this;
   }
-  int r = menu_->add(label,shortcut,callback,userdata,flags);
+  int r = menu_->insert(index,label,shortcut,callback,userdata,flags);
   // if it rellocated array we must fix the pointer:
   int value_offset = value_-menu_;
   menu_ = local_array; // in case it reallocated it