From c148f591b4cf2a435016345eb67e13b713c67952 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 31 May 2024 11:15:45 +0200 Subject: [PATCH] Proposing a fix for issue #1722: add a '...' menu to hold the dynamic parts --- src/lay/lay/layMainWindow.cc | 4 ++ src/laybasic/laybasic/layAbstractMenu.cc | 77 +++++++++++++++++++++++- src/laybasic/laybasic/layAbstractMenu.h | 10 +++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index d9c7fe0a7..51bc51462 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -4350,6 +4350,10 @@ public: menu_entries.push_back (lay::submenu ("zoom_menu", at, tl::to_string (QObject::tr ("&Display")))); menu_entries.push_back (lay::submenu ("tools_menu", at, tl::to_string (QObject::tr ("&Tools")))); menu_entries.push_back (lay::submenu ("macros_menu", at, tl::to_string (QObject::tr ("&Macros")))); + if (lay::AbstractMenu::wants_extra_menu ()) { + // for MacOS + menu_entries.push_back (lay::submenu (lay::AbstractMenu::extra_menu_name (), at, "...")); + } menu_entries.push_back (lay::separator ("help_group", at)); menu_entries.push_back (lay::submenu ("help_menu", at, tl::to_string (QObject::tr ("&Help")))); menu_entries.push_back (lay::submenu ("@secrets", at, tl::to_string (QObject::tr ("Secret Features")))); diff --git a/src/laybasic/laybasic/layAbstractMenu.cc b/src/laybasic/laybasic/layAbstractMenu.cc index a63b4c49c..4ff569aca 100644 --- a/src/laybasic/laybasic/layAbstractMenu.cc +++ b/src/laybasic/laybasic/layAbstractMenu.cc @@ -1225,6 +1225,36 @@ static QAction *insert_action_after (QWidget *widget, QAction *after, QAction *a return action; } +static const std::string s_extras_menu_name ("_extras_menu"); + +static QMenu *find_extras_menu (QMenuBar *mbar) +{ + if (! mbar) { + return 0; + } + + QList a = mbar->actions (); + for (QList::const_iterator i = a.begin (); i != a.end (); ++i) { + if (tl::to_string ((*i)->objectName ()) == s_extras_menu_name) { + return (*i)->menu (); + } + } + + return 0; +} + +bool +AbstractMenu::wants_extra_menu () +{ + return !s_can_move_menu; +} + +const std::string & +AbstractMenu::extra_menu_name () +{ + return s_extras_menu_name; +} + void AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) { @@ -1234,10 +1264,22 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) std::set > present_actions; if (mbar) { + QList a = mbar->actions (); for (QList::const_iterator i = a.begin (); i != a.end (); ++i) { present_actions.insert (std::make_pair (id_from_action (*i), *i)); } + + } + + // NOTE: on MacOS, once the top level menu is created, we should not + // modify it and place menu items into the "Extras" menu instead. + bool menu_frozen = ! s_can_move_menu && ! present_actions.empty (); + + // NOTE: the "extras" menu is relevant on MacOS only + QMenu *extras_menu = find_extras_menu (mbar); + if (extras_menu) { + extras_menu->clear (); } QAction *prev_action = 0; @@ -1277,11 +1319,25 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) } else if (mbar) { if (c->menu () == 0) { + QMenu *menu = new QMenu (mp_dispatcher->menu_parent_widget ()); menu->setTitle (tl::to_qstring (c->action ()->get_title ())); c->set_action (new Action (menu), true); - prev_action = insert_action_after (mbar, prev_action, menu->menuAction ()); + + // This case happens when we dynamically create menus. + // MacOS does not like generating top-level menus dynamically, so + // we put them into the "_extra" top level one. + if (menu_frozen) { + QMenu *extras_menu = find_extras_menu (mbar); + if (extras_menu) { + extras_menu->addMenu (menu); + } + } else { + prev_action = insert_action_after (mbar, prev_action, menu->menuAction ()); + } + } else { + // Move the action to the end if present in the menu already std::set >::iterator a = present_actions.find (std::make_pair (id_from_action (c->menu ()->menuAction ()), c->menu ()->menuAction ())); if (a != present_actions.end ()) { @@ -1291,9 +1347,15 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) } prev_action = a->second; present_actions.erase (*a); + } else if (menu_frozen) { + QMenu *extras_menu = find_extras_menu (mbar); + if (extras_menu) { + extras_menu->addMenu (c->menu ()); + } } else { prev_action = insert_action_after (mbar, prev_action, c->menu ()->menuAction ()); } + } build (c->menu (), c->children); @@ -1311,6 +1373,11 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) } prev_action = a->second; present_actions.erase (*a); + } else if (menu_frozen) { + QMenu *extras_menu = find_extras_menu (mbar); + if (extras_menu) { + extras_menu->addAction (c->action ()->qaction ()); + } } else { prev_action = insert_action_after (mbar, prev_action, c->action ()->qaction ()); } @@ -1319,8 +1386,14 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar) } + // Disable the (maybe new) "extras" menu if empty + extras_menu = find_extras_menu (mbar); + if (extras_menu) { + extras_menu->setEnabled (! extras_menu->isEmpty ()); + } + // Remove all actions that have vanished - if (mbar) { + if (mbar && s_can_move_menu) { for (std::set >::iterator a = present_actions.begin (); a != present_actions.end (); ++a) { mbar->removeAction (a->second); } diff --git a/src/laybasic/laybasic/layAbstractMenu.h b/src/laybasic/laybasic/layAbstractMenu.h index 272d8131a..aec72ac7a 100644 --- a/src/laybasic/laybasic/layAbstractMenu.h +++ b/src/laybasic/laybasic/layAbstractMenu.h @@ -692,6 +692,16 @@ public: */ ~AbstractMenu (); + /** + * @brief Returns a value indicating that a special "extras" menu is needed + */ + static bool wants_extra_menu (); + + /** + * @brief Returns the name of the special "extras" menu + */ + static const std::string &extra_menu_name (); + #if defined(HAVE_QT) /** * @brief Rebuild the QMenu's and refill the QMenuBar object