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());