diff --git a/src/app/app_menus.cpp b/src/app/app_menus.cpp index 7037cb41c..1b830942f 100644 --- a/src/app/app_menus.cpp +++ b/src/app/app_menus.cpp @@ -638,7 +638,7 @@ void AppMenus::removeMenuGroup(const std::string& groupId) } void AppMenus::addMenuItemIntoGroup(const std::string& groupId, - std::unique_ptr&& menuItem) + std::unique_ptr&& menuItem) { GroupInfo& group = m_groups[groupId]; diff --git a/src/app/app_menus.h b/src/app/app_menus.h index 939a035f4..1f7aa1052 100644 --- a/src/app/app_menus.h +++ b/src/app/app_menus.h @@ -64,7 +64,7 @@ namespace app { MenuItem* menuItem); void removeMenuGroup(const std::string& groupId); void addMenuItemIntoGroup(const std::string& groupId, - std::unique_ptr&& menuItem); + std::unique_ptr&& menuItem); void removeMenuItemFromGroup(Command* cmd); void removeMenuItemFromGroup(Widget* menuItem); diff --git a/src/app/extensions.cpp b/src/app/extensions.cpp index 092ee4cc8..d9d89992b 100644 --- a/src/app/extensions.cpp +++ b/src/app/extensions.cpp @@ -26,6 +26,7 @@ #include "base/fs.h" #include "base/fstream_path.h" #include "render/dithering_matrix.h" +#include "ui/widget.h" #if ENABLE_SENTRY #include "app/sentry_wrapper.h" @@ -340,6 +341,14 @@ void Extension::removeMenuGroup(const std::string& id) } } +void Extension::addMenuSeparator(ui::Widget* widget) +{ + PluginItem item; + item.type = PluginItem::MenuSeparator; + item.widget = widget; + m_plugin.items.push_back(item); +} + #endif bool Extension::canBeDisabled() const @@ -710,9 +719,9 @@ void Extension::exitScripts() m_plugin.pluginRef = LUA_REFNIL; } - // Remove plugin items automatically (first commands, then menu - // groups) - for (const auto& item : m_plugin.items) { + // Remove plugin items automatically: first commands and menu + // separators, then menu groups. + for (auto& item : m_plugin.items) { if (item.type == PluginItem::Command) { auto cmds = Commands::instance(); auto cmd = cmds->byId(item.id.c_str()); @@ -731,6 +740,19 @@ void Extension::exitScripts() delete cmd; } } + else if (item.type == PluginItem::MenuSeparator) { +#ifdef ENABLE_UI + ASSERT(item.widget); + ASSERT(item.widget->parent()); + if (item.widget && + item.widget->parent()) { + // TODO use a signal + AppMenus::instance()->removeMenuItemFromGroup(item.widget); + ASSERT(!item.widget->parent()); + item.widget = nullptr; + } +#endif // ENABLE_UI + } } for (const auto& item : m_plugin.items) { diff --git a/src/app/extensions.h b/src/app/extensions.h index 9e2378166..e1ddb8755 100644 --- a/src/app/extensions.h +++ b/src/app/extensions.h @@ -16,6 +16,10 @@ #include #include +namespace ui { + class Widget; +} + namespace app { // Key=id @@ -114,6 +118,8 @@ namespace app { void addMenuGroup(const std::string& id); void removeMenuGroup(const std::string& id); + + void addMenuSeparator(ui::Widget* widget); #endif bool isEnabled() const { return m_isEnabled; } @@ -158,9 +164,10 @@ namespace app { ScriptItem(const std::string& fn); }; struct PluginItem { - enum Type { Command, MenuGroup }; + enum Type { Command, MenuGroup, MenuSeparator }; Type type; std::string id; + ui::Widget* widget = nullptr; }; struct Plugin { int pluginRef; diff --git a/src/app/script/plugin_class.cpp b/src/app/script/plugin_class.cpp index 64292e662..466391254 100644 --- a/src/app/script/plugin_class.cpp +++ b/src/app/script/plugin_class.cpp @@ -227,7 +227,7 @@ int Plugin_newMenuGroup(lua_State* L) lua_pop(L, 1); if (id.empty()) - return luaL_error(L, "Empty id field in plugin:newCommand{ id=... }"); + return luaL_error(L, "Empty id field in plugin:newMenuGroup{ id=... }"); lua_getfield(L, 2, "title"); if (const char* s = lua_tostring(L, -1)) { @@ -286,6 +286,33 @@ int Plugin_deleteMenuGroup(lua_State* L) return 0; } +int Plugin_newMenuSeparator(lua_State* L) +{ + auto plugin = get_obj(L, 1); + if (lua_istable(L, 2)) { + std::string group; + + lua_getfield(L, 2, "group"); // Parent group + if (const char* s = lua_tostring(L, -1)) { + group = s; + } + lua_pop(L, 1); + +#ifdef ENABLE_UI + // Add a new separator if the "group" is defined + if (!group.empty() && + App::instance()->isGui()) { // On CLI menus do not make sense + if (auto appMenus = AppMenus::instance()) { + auto menuItem = std::make_unique(); + plugin->ext->addMenuSeparator(menuItem.get()); + appMenus->addMenuItemIntoGroup(group, std::move(menuItem)); + } + } +#endif // ENABLE_UI + } + return 0; +} + int Plugin_get_preferences(lua_State* L) { if (!lua_getuservalue(L, 1)) { @@ -309,6 +336,7 @@ const luaL_Reg Plugin_methods[] = { { "deleteCommand", Plugin_deleteCommand }, { "newMenuGroup", Plugin_newMenuGroup }, { "deleteMenuGroup", Plugin_deleteMenuGroup }, + { "newMenuSeparator", Plugin_newMenuSeparator }, { nullptr, nullptr } };