diff options
| author | Matthias Melcher <github@matthiasm.com> | 2025-04-01 17:00:51 +0200 |
|---|---|---|
| committer | Matthias Melcher <github@matthiasm.com> | 2025-04-01 17:00:56 +0200 |
| commit | f4978a014997656b4592c2b3b866865f76d390ea (patch) | |
| tree | 13a365c34b705942195c75fd3186801976786070 | |
| parent | 0eb6bb8e6d34b39399cda8b768851a3218eb7e2c (diff) | |
Adding the FL_MENU_CHATTY flag to Fl_Menu_Item.
If set, menu items will also call the callback when highlighting changes.
The reason is given with Fl::callback_reason(). #941
| -rw-r--r-- | FL/Fl_Menu_Item.H | 28 | ||||
| -rw-r--r-- | src/Fl_MacOS_Sys_Menu_Bar.mm | 2 | ||||
| -rw-r--r-- | src/Fl_Menu.cxx | 21 | ||||
| -rw-r--r-- | src/Fl_Menu_.cxx | 7 | ||||
| -rw-r--r-- | test/menubar.cxx | 16 |
5 files changed, 63 insertions, 11 deletions
diff --git a/FL/Fl_Menu_Item.H b/FL/Fl_Menu_Item.H index 3073dd2d0..6eaf0a9d2 100644 --- a/FL/Fl_Menu_Item.H +++ b/FL/Fl_Menu_Item.H @@ -34,7 +34,8 @@ enum { // values for flags: FL_SUBMENU_POINTER = 0x20, ///< Indicates user_data() is a pointer to another menu array FL_SUBMENU = 0x40, ///< Item is a submenu to other items FL_MENU_DIVIDER = 0x80, ///< Creates divider line below this item. Also ends a group of radio buttons - FL_MENU_HORIZONTAL = 0x100 ///< ??? -- reserved, internal (do not use) + FL_MENU_HORIZONTAL = 0x100, ///< reserved, do not use + FL_MENU_CHATTY = 0x200 ///< Menu Item receives additional callbacks ///< Note: \b ALL other bits in \p flags are reserved: do not use them for your own purposes! }; @@ -67,7 +68,8 @@ class Fl_Menu_; FL_SUBMENU_POINTER = 0x20, // Indicates user_data() is a pointer to another menu array FL_SUBMENU = 0x40, // This item is a submenu to other items FL_MENU_DIVIDER = 0x80, // Creates divider line below this item. Also ends a group of radio buttons. - FL_MENU_HORIZONTAL = 0x100 // ??? -- reserved, internal (do not use) + FL_MENU_HORIZONTAL = 0x100 // reserved, do not use + FL_MENU_CHATTY = 0x200 ///< Menu Item receives additional callbacks }; \endcode @@ -120,6 +122,16 @@ class Fl_Menu_; variants copies the entire menu to internal storage. Using the memory of a static menu array after that would access unused (but not released) memory and thus have no effect. + + When a menu item is selected by the user and a callback is set, the callback + will be called with FL_REASON_SELECTED. The Fl_Widget pointer is set to the + widget that opened the menu, a copy of the menu item's user data. If no menu + item callback is set, the callback of the managing widget is called instead. + + If the FL_MENU_CHATTY flag is set, the menu item callback may be called for + additional reasons. When a menu item is highlighted, the callback is called + with FL_REASON_GOT_FOCUS. If it is no longer highlighted, + FL_REASON_LOST_FOCUS is sent. */ struct FL_EXPORT Fl_Menu_Item { const char *text; ///< menu item text, returned by label() @@ -490,14 +502,18 @@ struct FL_EXPORT Fl_Menu_Item { The callback is called with the stored user_data() as its second argument. You must first check that callback() is non-zero before calling this. */ - void do_callback(Fl_Widget* o) const {Fl::callback_reason_=FL_REASON_SELECTED; callback_(o, user_data_);} + void do_callback(Fl_Widget* o, Fl_Callback_Reason reason=FL_REASON_UNKNOWN) const { + Fl::callback_reason_ = reason; callback_(o, user_data_); + } /** Calls the Fl_Menu_Item item's callback, and provides the Fl_Widget argument. This call overrides the callback's second argument with the given value \p arg. You must first check that callback() is non-zero before calling this. */ - void do_callback(Fl_Widget* o,void* arg) const {Fl::callback_reason_=FL_REASON_SELECTED; callback_(o, arg);} + void do_callback(Fl_Widget* o, void* arg, Fl_Callback_Reason reason=FL_REASON_UNKNOWN) const { + Fl::callback_reason_ = reason; callback_(o, arg); + } /** Calls the Fl_Menu_Item item's callback, and provides the Fl_Widget argument. @@ -506,7 +522,9 @@ struct FL_EXPORT Fl_Menu_Item { the callback. You must first check that callback() is non-zero before calling this. */ - void do_callback(Fl_Widget* o,long arg) const {Fl::callback_reason_=FL_REASON_SELECTED; callback_(o, (void*)(fl_intptr_t)arg);} + void do_callback(Fl_Widget* o, long arg, Fl_Callback_Reason reason=FL_REASON_UNKNOWN) const { + Fl::callback_reason_ = FL_REASON_SELECTED; callback_(o, (void*)(fl_intptr_t)arg); + } /** Back compatibility only. \deprecated diff --git a/src/Fl_MacOS_Sys_Menu_Bar.mm b/src/Fl_MacOS_Sys_Menu_Bar.mm index b76deb27e..87c5089cd 100644 --- a/src/Fl_MacOS_Sys_Menu_Bar.mm +++ b/src/Fl_MacOS_Sys_Menu_Bar.mm @@ -167,7 +167,7 @@ const char *Fl_Mac_App_Menu::quit = "Quit %@"; { fl_lock_function(); Fl_Menu_Item *item = (Fl_Menu_Item *)[(NSData*)[self representedObject] bytes]; - if ( item && item->callback() ) item->do_callback(NULL); + if ( item && item->callback() ) item->do_callback(NULL, FL_REASON_SELECTED); fl_unlock_function(); } - (void) setKeyEquivalentModifierMask:(int)value diff --git a/src/Fl_Menu.cxx b/src/Fl_Menu.cxx index 500b20a5c..a91666ad3 100644 --- a/src/Fl_Menu.cxx +++ b/src/Fl_Menu.cxx @@ -146,6 +146,7 @@ class menuwindow : public window_with_items { public: menutitle* title; int handle(int) FL_OVERRIDE; + void hide() override; int itemheight; // zero == menubar int numitems; int selected; @@ -480,6 +481,11 @@ menuwindow::~menuwindow() { delete title; } +void menuwindow::hide() { + set_selected(-1); + window_with_items::hide(); +} + void menuwindow::position(int X, int Y) { if (title) {title->position(X, title->y()+Y-y());} Fl_Menu_Window::position(X, Y); @@ -592,7 +598,20 @@ void menuwindow::draw() { } void menuwindow::set_selected(int n) { - if (n != selected) {selected = n; damage(FL_DAMAGE_CHILD);} + if (n != selected) { + if ((selected!=-1) && (menu)) { + const Fl_Menu_Item *mi = menu->next(selected); + if ((mi) && (mi->callback_) && (mi->flags & FL_MENU_CHATTY)) + mi->do_callback(this, FL_REASON_LOST_FOCUS); + } + selected = n; + if ((selected!=-1) && (menu)) { + const Fl_Menu_Item *mi = menu->next(selected); + if ((mi) && (mi->callback_) && (mi->flags & FL_MENU_CHATTY)) + mi->do_callback(this, FL_REASON_GOT_FOCUS); + } + damage(FL_DAMAGE_CHILD); + } } //////////////////////////////////////////////////////////////// diff --git a/src/Fl_Menu_.cxx b/src/Fl_Menu_.cxx index 20964e748..6a34278ff 100644 --- a/src/Fl_Menu_.cxx +++ b/src/Fl_Menu_.cxx @@ -401,8 +401,11 @@ const Fl_Menu_Item* Fl_Menu_::picked(const Fl_Menu_Item* v) { value_ = v; if (when()&(FL_WHEN_CHANGED|FL_WHEN_RELEASE)) { if (changed() || when()&FL_WHEN_NOT_CHANGED) { - if (value_ && value_->callback_) value_->do_callback((Fl_Widget*)this); - else do_callback(); + if (value_ && value_->callback_) { + value_->do_callback((Fl_Widget*)this, value_->user_data(), FL_REASON_SELECTED); + } else { + do_callback(FL_REASON_SELECTED); + } } } } diff --git a/test/menubar.cxx b/test/menubar.cxx index 6cf22458a..355921eba 100644 --- a/test/menubar.cxx +++ b/test/menubar.cxx @@ -61,7 +61,19 @@ void test_cb(Fl_Widget* w, void*) { G_tty->printf("%s\n", m->label()); } -void quit_cb(Fl_Widget*, void*) {exit(0);} +void quit_cb(Fl_Widget*, void*) { + switch (Fl::callback_reason()) { + case FL_REASON_SELECTED: + exit(0); + case FL_REASON_GOT_FOCUS: + G_tty->printf("Selecting this menu item will quit this application!\n"); + break; + case FL_REASON_LOST_FOCUS: + G_tty->printf("Risk of quitting averted.\n"); + break; + default: break; + } +} Fl_Menu_Item hugemenu[100]; @@ -70,7 +82,7 @@ Fl_Menu_Item menutable[] = { {"&File",0,0,0,FL_SUBMENU}, {"&Open", FL_ALT+'o', 0, 0, FL_MENU_INACTIVE}, {"&Close", 0, 0}, - {"&Quit", FL_ALT+'q', quit_cb, 0, FL_MENU_DIVIDER}, + {"&Quit", FL_ALT+'q', quit_cb, 0, FL_MENU_DIVIDER|FL_MENU_CHATTY}, #if (OVERRIDE_SCALING_SHORTCUTS) {"CTRL/0", FL_COMMAND+'0', 0}, |
