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
This commit is contained in:
Albrecht Schlosser 2010-11-11 09:12:05 +00:00
parent 832c8787ab
commit 2105f203f1
7 changed files with 106 additions and 36 deletions

View File

@ -1,6 +1,7 @@
CHANGES IN FLTK 1.3.0 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 fltk-config to give --libs on one line (STR #2408)
- Fixed tab key navigation to inactive widgets (STR #2420) - Fixed tab key navigation to inactive widgets (STR #2420)
- Fixed outside label redraw damage areas (STR #2436) - Fixed outside label redraw damage areas (STR #2436)

View File

@ -70,6 +70,17 @@ public:
int find_index(const Fl_Menu_Item *item) const; int find_index(const Fl_Menu_Item *item) const;
int find_index(Fl_Callback *cb) 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());} const Fl_Menu_Item* test_shortcut() {return picked(menu()->test_shortcut());}
void global(); void global();
@ -118,7 +129,7 @@ public:
int value(int i) {return value(menu_+i);} int value(int i) {return value(menu_+i);}
/** Returns the title of the last item chosen. */ /** Returns the title of the last item chosen. */
const char *text() const {return value_ ? value_->text : 0;} 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;} const char *text(int i) const {return menu_[i].text;}
/** Gets the current font of menu item labels. */ /** Gets the current font of menu item labels. */

View File

@ -349,7 +349,7 @@ struct FL_EXPORT Fl_Menu_Item {
const Fl_Menu_Item* title = 0, const Fl_Menu_Item* title = 0,
int menubar=0) const; int menubar=0) const;
const Fl_Menu_Item* test_shortcut() 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 Calls the Fl_Menu_Item item's callback, and provides the

View File

@ -845,12 +845,12 @@ public:
// Documentation and implementation in Fl_Widget.cxx // Documentation and implementation in Fl_Widget.cxx
void do_callback(Fl_Widget* o,void* arg=0); void do_callback(Fl_Widget* o,void* arg=0);
/** Internal use only. */ /* Internal use only. */
int test_shortcut(); int test_shortcut();
/** Internal use only. */ /* Internal use only. */
static unsigned int label_shortcut(const char *t); static unsigned int label_shortcut(const char *t);
/** Internal use only. */ /* Internal use only. */
static int test_shortcut(const char*); static int test_shortcut(const char*, const bool require_alt = false);
/** Checks if w is a child of this widget. /** Checks if w is a child of this widget.
\param[in] w potential child widget \param[in] w potential child widget

View File

@ -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 This method is called by widgets that want to display menus.
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 The menu stays up until the user picks an item or dismisses it.
callbacks or change the state of check or radio items.</I> The selected item (or NULL if none) is returned. <I>This does not
<P>X,Y is the position of the mouse cursor, relative to the 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 window that got the most recent event (usually you can pass
Fl::event_x() and Fl::event_y() unchanged here). </P> 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. </P> \p title is a character string title for the menu. If
<P>The menu is positioned so the cursor is centered over the item non-zero a small box appears above the menu with the title in it.
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 The menu is positioned so the cursor is centered over the item
positioned with the cursor in the top-left corner. </P> picked. This will work even if \p picked is in a submenu.
<P>button is a pointer to an If \p picked is zero or not in the menu item table the menu is
Fl_Menu_ from which the color and boxtypes for the menu are positioned with the cursor in the top-left corner.
pulled. If NULL then defaults are used.
\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( const Fl_Menu_Item* Fl_Menu_Item::popup(
int X, int Y, int X, int Y,
const char* title, const char* title,
const Fl_Menu_Item* picked, const Fl_Menu_Item* picked,
const Fl_Menu_* but const Fl_Menu_* button
) const { ) const {
static Fl_Menu_Item dummy; // static so it is all zeros static Fl_Menu_Item dummy; // static so it is all zeros
dummy.text = title; 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. 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(); const Fl_Menu_Item* m = first();
if (m) for (int ii = 0; m->text; m = m->next(), ii++) { if (m) for (int ii = 0; m->text; m = m->next(), ii++) {
if (m->activevisible()) { if (m->activevisible()) {
if (Fl::test_shortcut(m->shortcut_) if (Fl::test_shortcut(m->shortcut_)
|| Fl_Widget::test_shortcut(m->text)) { || Fl_Widget::test_shortcut(m->text, require_alt)) {
if (ip) *ip=ii; if (ip) *ip=ii;
return m; return m;
} }

View File

@ -65,7 +65,7 @@ int Fl_Menu_Bar::handle(int event) {
return 1; return 1;
case FL_SHORTCUT: case FL_SHORTCUT:
if (visible_r()) { if (visible_r()) {
v = menu()->find_shortcut(); v = menu()->find_shortcut(0, true);
if (v && v->submenu()) goto J1; if (v && v->submenu()) goto J1;
} }
return test_shortcut() != 0; return test_shortcut() != 0;

View File

@ -54,9 +54,11 @@
/** /**
Test the current event, which must be an FL_KEYBOARD or Test the current event, which must be an FL_KEYBOARD or
FL_SHORTCUT, against a shortcut value (described in FL_SHORTCUT, against a shortcut value (described in
Fl_Button). Returns non-zero if there is a match. Not to Fl_Button).
be confused with
Fl_Widget::test_shortcut(). Not to be confused with Fl_Widget::test_shortcut().
\return non-zero if there is a match.
*/ */
int Fl::test_shortcut(unsigned int shortcut) { int Fl::test_shortcut(unsigned int shortcut) {
if (!shortcut) return 0; if (!shortcut) return 0;
@ -292,6 +294,18 @@ unsigned int fl_old_shortcut(const char* s) {
// Tests for &x shortcuts in button labels: // 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) { unsigned int Fl_Widget::label_shortcut(const char *t) {
if (!t) return 0; if (!t) return 0;
for (;;) { for (;;) {
@ -306,12 +320,29 @@ unsigned int Fl_Widget::label_shortcut(const char *t) {
} }
} }
int Fl_Widget::test_shortcut(const char *t) { /** Returns true if the given text \p t contains the entered '&x' shortcut.
#ifdef WIN32
// on MSWindows, users expect shortcuts to work only when the Alt modifier is pressed This method must only be called in handle() methods or callbacks after
if (Fl::event_state(FL_ALT)==0) return 0; a keypress event (usually FL_KEYDOWN or FL_SHORTCUT). The given text
#endif \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; 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); unsigned int c = fl_utf8decode(Fl::event_text(), Fl::event_text()+Fl::event_length(), 0);
if (!c) return 0; if (!c) return 0;
if (c == label_shortcut(t)) if (c == label_shortcut(t))
@ -319,6 +350,21 @@ int Fl_Widget::test_shortcut(const char *t) {
return 0; 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() { int Fl_Widget::test_shortcut() {
if (!(flags()&SHORTCUT_LABEL)) return 0; if (!(flags()&SHORTCUT_LABEL)) return 0;
return test_shortcut(label()); return test_shortcut(label());