From 2105f203f18ef44e4710fc07148f1a2e5376cc68 Mon Sep 17 00:00:00 2001
From: Albrecht Schlosser <albrechts.fltk@online.de>
Date: Thu, 11 Nov 2010 09:12:05 +0000
Subject: [PATCH] Fixed menu and shortcut handling (STR #2243). This partly
 reverts the fix for STR #2199 - for details see STR #2243.

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@7816 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
---
 CHANGES             |  3 ++-
 FL/Fl_Menu_.H       | 13 +++++++++-
 FL/Fl_Menu_Item.H   |  2 +-
 FL/Fl_Widget.H      |  8 +++---
 src/Fl_Menu.cxx     | 52 ++++++++++++++++++++++---------------
 src/Fl_Menu_Bar.cxx |  2 +-
 src/fl_shortcut.cxx | 62 +++++++++++++++++++++++++++++++++++++++------
 7 files changed, 106 insertions(+), 36 deletions(-)

diff --git a/CHANGES b/CHANGES
index 95420c832..a76dcd7e3 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,7 @@
 CHANGES IN FLTK 1.3.0
 
-	- removed support for gcc 2.x (or older)
+	- Fixed menu and shortcut handling (STR #2243)
+	- Removed support for gcc 2.x (or older)
 	- Fixed fltk-config to give --libs on one line (STR #2408)
 	- Fixed tab key navigation to inactive widgets (STR #2420)
 	- Fixed outside label redraw damage areas (STR #2436)
diff --git a/FL/Fl_Menu_.H b/FL/Fl_Menu_.H
index 7cb4cd18e..4b4e4f30f 100644
--- a/FL/Fl_Menu_.H
+++ b/FL/Fl_Menu_.H
@@ -70,6 +70,17 @@ public:
   int find_index(const Fl_Menu_Item *item) const;
   int find_index(Fl_Callback *cb) const;
 
+  /**
+    Returns the menu item with the entered shortcut (key value).
+
+    This searches the complete menu() for a shortcut that matches the
+    entered key value.  It must be called for a FL_KEYBOARD or FL_SHORTCUT
+    event.
+
+    If a match is found, the menu's callback will be called.
+
+    \return matched Fl_Menu_Item or NULL.
+  */
   const Fl_Menu_Item* test_shortcut() {return picked(menu()->test_shortcut());}
   void global();
 
@@ -118,7 +129,7 @@ public:
   int value(int i) {return value(menu_+i);}
   /** Returns the title of the last item chosen.  */
   const char *text() const {return value_ ? value_->text : 0;}
-  /** Returns the title of the last item chosen, or of item i.  */
+  /** Returns the title of item i.  */
   const char *text(int i) const {return menu_[i].text;}
 
   /** Gets the current font of menu item labels.  */
diff --git a/FL/Fl_Menu_Item.H b/FL/Fl_Menu_Item.H
index 31620e16f..7dde44720 100644
--- a/FL/Fl_Menu_Item.H
+++ b/FL/Fl_Menu_Item.H
@@ -349,7 +349,7 @@ struct FL_EXPORT Fl_Menu_Item {
     const Fl_Menu_Item* title = 0,
     int menubar=0) const;
   const Fl_Menu_Item* test_shortcut() const;
-  const Fl_Menu_Item* find_shortcut(int *ip=0) const;
+  const Fl_Menu_Item* find_shortcut(int *ip=0, const bool require_alt = false) const;
 
   /**
     Calls the Fl_Menu_Item item's callback, and provides the 
diff --git a/FL/Fl_Widget.H b/FL/Fl_Widget.H
index 0b89ad9eb..d20ee6b7e 100644
--- a/FL/Fl_Widget.H
+++ b/FL/Fl_Widget.H
@@ -845,12 +845,12 @@ public:
   // Documentation and implementation in Fl_Widget.cxx
   void do_callback(Fl_Widget* o,void* arg=0);
 
-  /** Internal use only. */
+  /* Internal use only. */
   int test_shortcut();
-  /** Internal use only. */
+  /* Internal use only. */
   static unsigned int label_shortcut(const char *t);
-  /** Internal use only. */
-  static int test_shortcut(const char*);
+  /* Internal use only. */
+  static int test_shortcut(const char*, const bool require_alt = false);
 
   /** Checks if w is a child of this widget.
       \param[in] w potential child widget
diff --git a/src/Fl_Menu.cxx b/src/Fl_Menu.cxx
index e341b868a..7f9df8e1f 100644
--- a/src/Fl_Menu.cxx
+++ b/src/Fl_Menu.cxx
@@ -956,44 +956,56 @@ const Fl_Menu_Item* Fl_Menu_Item::pulldown(
 }
 
 /**
-  This method is called by widgets that want to display menus.  The menu
-  stays up until the user picks an item or dismisses it.  The selected
-  item (or NULL if none) is returned. <I>This does not do the
-  callbacks or change the state of check or radio items.</I>
-  <P>X,Y is the position of the mouse cursor, relative to the
+  This method is called by widgets that want to display menus.
+
+  The menu stays up until the user picks an item or dismisses it.
+  The selected item (or NULL if none) is returned. <I>This does not
+  do the callbacks or change the state of check or radio items.</I>
+
+  X,Y is the position of the mouse cursor, relative to the
   window that got the most recent event (usually you can pass 
-  Fl::event_x() and Fl::event_y() unchanged here). </P>
-  <P>title is a character string title for the menu.  If
-  non-zero a small box appears above the menu with the title in it. </P>
-  <P>The menu is positioned so the cursor is centered over the item 
-  picked.  This will work even if picked is in a submenu.
-  If picked is zero or not in the menu item table the menu is
-  positioned with the cursor in the top-left corner. </P>
-  <P>button is a pointer to an 
-  Fl_Menu_ from which the color and boxtypes for the menu are
-  pulled.  If NULL then defaults are used.
+  Fl::event_x() and Fl::event_y() unchanged here).
+
+  \p title is a character string title for the menu.  If
+  non-zero a small box appears above the menu with the title in it.
+
+  The menu is positioned so the cursor is centered over the item 
+  picked.  This will work even if \p picked is in a submenu.
+  If \p picked is zero or not in the menu item table the menu is
+  positioned with the cursor in the top-left corner.
+
+  \p button is a pointer to an Fl_Menu_ from which the color and
+  boxtypes for the menu are pulled.  If NULL then defaults are used.
 */
 const Fl_Menu_Item* Fl_Menu_Item::popup(
   int X, int Y,
   const char* title,
   const Fl_Menu_Item* picked,
-  const Fl_Menu_* but
+  const Fl_Menu_* button
   ) const {
   static Fl_Menu_Item dummy; // static so it is all zeros
   dummy.text = title;
-  return pulldown(X, Y, 0, 0, picked, but, title ? &dummy : 0);
+  return pulldown(X, Y, 0, 0, picked, button, title ? &dummy : 0);
 }
 
 /**
   Search only the top level menu for a shortcut.  
-  Either &x in the label or the shortcut fields are used. 
+  Either &x in the label or the shortcut fields are used.
+
+  This tests the current event, which must be an FL_KEYBOARD or 
+  FL_SHORTCUT, against a shortcut value.
+
+  \param ip returns the index of the item, if \p ip is not NULL.
+  \param require_alt if true: match only if Alt key is pressed.
+
+  \return found Fl_Menu_Item or NULL
 */
-const Fl_Menu_Item* Fl_Menu_Item::find_shortcut(int* ip) const {
+const Fl_Menu_Item* Fl_Menu_Item::find_shortcut(int* ip, const bool require_alt) const {
   const Fl_Menu_Item* m = first();
   if (m) for (int ii = 0; m->text; m = m->next(), ii++) {
     if (m->activevisible()) {
       if (Fl::test_shortcut(m->shortcut_)
-	 || Fl_Widget::test_shortcut(m->text)) {
+	 || Fl_Widget::test_shortcut(m->text, require_alt)) {
 	if (ip) *ip=ii;
 	return m;
       }
diff --git a/src/Fl_Menu_Bar.cxx b/src/Fl_Menu_Bar.cxx
index 06a0003a2..c178805c2 100644
--- a/src/Fl_Menu_Bar.cxx
+++ b/src/Fl_Menu_Bar.cxx
@@ -65,7 +65,7 @@ int Fl_Menu_Bar::handle(int event) {
     return 1;
   case FL_SHORTCUT:
     if (visible_r()) {
-      v = menu()->find_shortcut();
+      v = menu()->find_shortcut(0, true);
       if (v && v->submenu()) goto J1;
     }
     return test_shortcut() != 0;
diff --git a/src/fl_shortcut.cxx b/src/fl_shortcut.cxx
index ecd47f158..dc93450fc 100644
--- a/src/fl_shortcut.cxx
+++ b/src/fl_shortcut.cxx
@@ -54,9 +54,11 @@
 /**
     Test the current event, which must be an FL_KEYBOARD or 
     FL_SHORTCUT, against a shortcut value (described in 
-    Fl_Button).  Returns non-zero if there is a match.  Not to
-    be confused with 
-    Fl_Widget::test_shortcut().
+    Fl_Button).
+    
+    Not to be confused with Fl_Widget::test_shortcut().
+    
+    \return non-zero if there is a match.
 */
 int Fl::test_shortcut(unsigned int shortcut) {
   if (!shortcut) return 0;
@@ -292,6 +294,18 @@ unsigned int fl_old_shortcut(const char* s) {
 
 // Tests for &x shortcuts in button labels:
 
+/** Returns the Unicode value of the '&x' shortcut in a given text.
+
+  The given text \p t (usually a widget's label or a menu text) is
+  searched for a '&x' shortcut label, and if found, the Unicode
+  value of the '&x' shortcut is returned.
+
+  \param t text or label to search for '&x' shortcut.
+
+  \return Unicode (UCS-4) value of shortcut in \p t or 0.
+
+  \note Internal use only.
+*/
 unsigned int Fl_Widget::label_shortcut(const char *t) {
   if (!t) return 0;
   for (;;) {
@@ -306,12 +320,29 @@ unsigned int Fl_Widget::label_shortcut(const char *t) {
   }
 }
 
-int Fl_Widget::test_shortcut(const char *t) {
-  #ifdef WIN32
-  // on MSWindows, users expect shortcuts to work only when the Alt modifier is pressed
-  if (Fl::event_state(FL_ALT)==0) return 0;
-  #endif
+/** Returns true if the given text \p t contains the entered '&x' shortcut.
+
+  This method must only be called in handle() methods or callbacks after
+  a keypress event (usually FL_KEYDOWN or FL_SHORTCUT). The given text
+  \p t (usually a widget's label or menu text) is searched for a '&x'
+  shortcut, and if found, this is compared with the entered key value.
+
+  Fl::event_text() is used to get the entered key value.
+  Fl::event_state() is used to get the Alt modifier, if \p require_alt
+  is true.
+
+  \param t text or label to search for '&x' shortcut.
+  \param require_alt if true: match only if Alt key is pressed.
+
+  \return true, if the entered text matches the '&x' shortcut in \p t
+	  false (0) otherwise.
+
+  \note Internal use only.
+*/
+int Fl_Widget::test_shortcut(const char *t, const bool require_alt) {
   if (!t) return 0;
+  // for menubars etc. shortcuts must work only if the Alt modifier is pressed
+  if (require_alt && Fl::event_state(FL_ALT)==0) return 0;
   unsigned int c = fl_utf8decode(Fl::event_text(), Fl::event_text()+Fl::event_length(), 0);
   if (!c) return 0;
   if (c == label_shortcut(t))
@@ -319,6 +350,21 @@ int Fl_Widget::test_shortcut(const char *t) {
   return 0;
 }
 
+/** Returns true if the widget's label contains the entered '&x' shortcut.
+
+  This method must only be called in handle() methods or callbacks after
+  a keypress event (usually FL_KEYDOWN or FL_SHORTCUT).
+  The widget's label is searched for a '&x'
+  shortcut, and if found, this is compared with the entered key value.
+
+  Fl::event_text() is used to get the entered key value.
+
+  \return true, if the entered text matches the widget's'&x' shortcut,
+	  false (0) otherwise.
+
+  \note Internal use only.
+*/
+
 int Fl_Widget::test_shortcut() {
   if (!(flags()&SHORTCUT_LABEL)) return 0;
   return test_shortcut(label());