From 71cfeb836a7df5a2527eebead5d6bf32964eb3e9 Mon Sep 17 00:00:00 2001 From: Andreas Butti Date: Fri, 22 Feb 2019 15:09:14 +0100 Subject: [PATCH 1/4] Ignore this eclipse config file --- .settings/language.settings.xml | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 .settings/language.settings.xml diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml deleted file mode 100644 index ca7c0739..00000000 --- a/.settings/language.settings.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - From d918ab4ea4cb22025148381dd967d11b1a60e2cc Mon Sep 17 00:00:00 2001 From: Andreas Butti Date: Fri, 22 Feb 2019 15:27:58 +0100 Subject: [PATCH 2/4] Ignore eclipse settings --- .settings/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .settings/.gitignore diff --git a/.settings/.gitignore b/.settings/.gitignore new file mode 100644 index 00000000..d81d4c41 --- /dev/null +++ b/.settings/.gitignore @@ -0,0 +1 @@ +/language.settings.xml From 04878851af3717aa8b0755e0bc6275a6f5b490c8 Mon Sep 17 00:00:00 2001 From: Andreas Butti Date: Fri, 22 Feb 2019 15:59:09 +0100 Subject: [PATCH 3/4] Lua API --- plugins/Example/main.lua | 3 +- src/plugin/Plugin.cpp | 9 ++++- src/plugin/luapi_application.h | 71 ++++++++++++++++------------------ src/util/XojMsgBox.cpp | 18 ++------- src/util/XojMsgBox.h | 11 ++---- 5 files changed, 48 insertions(+), 64 deletions(-) diff --git a/plugins/Example/main.lua b/plugins/Example/main.lua index 4a599d82..9090e7d9 100644 --- a/plugins/Example/main.lua +++ b/plugins/Example/main.lua @@ -15,5 +15,6 @@ end -- Callback if the menu item is executed function exampleCallback() - app.msgbox("Test123", "yes,no"); + result = app.msgbox("Test123", {[1] = "Yes", [2] = "No"}); + print("result = " .. result) end diff --git a/src/plugin/Plugin.cpp b/src/plugin/Plugin.cpp index 074942ee..93f2769c 100644 --- a/src/plugin/Plugin.cpp +++ b/src/plugin/Plugin.cpp @@ -1,6 +1,7 @@ #include "Plugin.h" #include +#include #ifdef ENABLE_PLUGINS @@ -315,7 +316,9 @@ void Plugin::loadScript() if (lua_pcall(lua, 0, 0, 0) != LUA_OK) { const char* errMsg = lua_tostring(lua, -1); - XojMsgBox::showPluginMessage(name, errMsg, MSG_BT_OK, true); + map button; + button.insert(std::pair(0, _("OK"))); + XojMsgBox::showPluginMessage(name, errMsg, button, true); g_warning("Could not run plugin Lua file: «%s», error: «%s»", luafile.c_str(), errMsg); this->valid = false; @@ -334,7 +337,9 @@ bool Plugin::callFunction(string fnc) if (lua_pcall(lua, 0, 0, 0)) { const char* errMsg = lua_tostring(lua, -1); - XojMsgBox::showPluginMessage(name, errMsg, MSG_BT_OK, true); + map button; + button.insert(std::pair(0, _("OK"))); + XojMsgBox::showPluginMessage(name, errMsg, button, true); g_warning("Error in Plugin: «%s», error: «%s»", name.c_str(), errMsg); return false; diff --git a/src/plugin/luapi_application.h b/src/plugin/luapi_application.h index 0e798e9c..61895114 100644 --- a/src/plugin/luapi_application.h +++ b/src/plugin/luapi_application.h @@ -12,43 +12,38 @@ #include #include +#include +using std::map; + /** * Example: - * app.msgbox("Test123", "yes,no") + * app.msgbox("Test123", {[1] = "Yes", [2] = "No"}) + * Return 1 for yes, 2 for no in this example */ static int applib_msgbox(lua_State* L) { const char* msg = luaL_checkstring(L, 1); - const char* flags = luaL_checkstring(L, 2); - int type = 0; - for (string element : StringUtils::split(flags, ',')) + // discard any extra arguments passed in + lua_settop(L, 2); + luaL_checktype(L, 2, LUA_TTABLE); + + lua_pushnil(L); + + map button; + + while (lua_next(L, 2) != 0) { - if (element == "ok") - { - type |= MSG_BT_OK; - } - else if (element == "yes") - { - type |= MSG_BT_YES; - } - else if (element == "no") - { - type |= MSG_BT_NO; - } - else if (element == "cancel") - { - type |= MSG_BT_CANCEL; - } - else - { - g_warning("Plugin: Unsupported button type for app.msgbox «%s»", element.c_str()); - } + int index = lua_tointeger(L, -2); + const char* buttonText = luaL_checkstring(L, -1); + lua_pop(L, 1); + + button.insert(button.begin(), std::pair(index, buttonText)); } Plugin* plugin = Plugin::getPluginFromLua(L); - int result = XojMsgBox::showPluginMessage(plugin->getName(), msg, type); + int result = XojMsgBox::showPluginMessage(plugin->getName(), msg, button); lua_pushinteger(L, result); return 1; } @@ -76,7 +71,7 @@ static int applib_registerUi(lua_State* L) lua_getfield(L, 1, "menu"); lua_getfield(L, 1, "callback"); // stack now has following: - // 1 = {"menu"="MenuName", callback="functionName"} + // 1 = {"menu"="MenuName", callback="functionName"} // -2 = "MenuName" // -1 = "functionName" @@ -119,10 +114,10 @@ static const luaL_Reg applib[] = { { "registerUi", applib_registerUi }, // Placeholder - {"MSG_BT_OK", NULL}, - {"MSG_BT_YES", NULL}, - {"MSG_BT_NO", NULL}, - {"MSG_BT_CANCEL", NULL}, +// {"MSG_BT_OK", NULL}, +// {"MSG_BT_YES", NULL}, +// {"MSG_BT_NO", NULL}, +// {"MSG_BT_CANCEL", NULL}, {NULL, NULL} }; @@ -133,14 +128,14 @@ static const luaL_Reg applib[] = { LUAMOD_API int luaopen_app(lua_State* L) { luaL_newlib(L, applib); - lua_pushnumber(L, MSG_BT_OK); - lua_setfield(L, -2, "MSG_BT_OK"); - lua_pushnumber(L, MSG_BT_YES); - lua_setfield(L, -2, "MSG_BT_YES"); - lua_pushnumber(L, MSG_BT_NO); - lua_setfield(L, -2, "MSG_BT_NO"); - lua_pushnumber(L, MSG_BT_CANCEL); - lua_setfield(L, -2, "MSG_BT_CANCEL"); +// lua_pushnumber(L, MSG_BT_OK); +// lua_setfield(L, -2, "MSG_BT_OK"); +// lua_pushnumber(L, MSG_BT_YES); +// lua_setfield(L, -2, "MSG_BT_YES"); +// lua_pushnumber(L, MSG_BT_NO); +// lua_setfield(L, -2, "MSG_BT_NO"); +// lua_pushnumber(L, MSG_BT_CANCEL); +// lua_setfield(L, -2, "MSG_BT_CANCEL"); return 1; } diff --git a/src/util/XojMsgBox.cpp b/src/util/XojMsgBox.cpp index 614f0efb..33fd9700 100644 --- a/src/util/XojMsgBox.cpp +++ b/src/util/XojMsgBox.cpp @@ -30,7 +30,7 @@ void XojMsgBox::showErrorToUser(GtkWindow* win, string msg) gtk_widget_destroy(dialog); } -int XojMsgBox::showPluginMessage(string pluginName, string msg, int type, bool error) +int XojMsgBox::showPluginMessage(string pluginName, string msg, map button, bool error) { string header = string("Xournal++ Plugin «") + pluginName + "»"; @@ -52,21 +52,9 @@ int XojMsgBox::showPluginMessage(string pluginName, string msg, int type, bool e g_object_set_property(G_OBJECT(dialog), "secondary-text", &val); g_value_unset(&val); - if (MSG_BT_OK & type) + for (auto& kv : button) { - gtk_dialog_add_button(GTK_DIALOG(dialog), _("OK"), MSG_BT_OK); - } - if (MSG_BT_YES & type) - { - gtk_dialog_add_button(GTK_DIALOG(dialog), _("Yes"), MSG_BT_YES); - } - if (MSG_BT_NO & type) - { - gtk_dialog_add_button(GTK_DIALOG(dialog), _("No"), MSG_BT_NO); - } - if (MSG_BT_CANCEL & type) - { - gtk_dialog_add_button(GTK_DIALOG(dialog), _("Cancel"), MSG_BT_CANCEL); + gtk_dialog_add_button(GTK_DIALOG(dialog), kv.second.c_str(), kv.first); } int res = gtk_dialog_run(GTK_DIALOG(dialog)); diff --git a/src/util/XojMsgBox.h b/src/util/XojMsgBox.h index d5c04dcb..7b9bde3c 100644 --- a/src/util/XojMsgBox.h +++ b/src/util/XojMsgBox.h @@ -15,13 +15,8 @@ #include using std::string; - -enum MsgBoxButtonType { - MSG_BT_OK = 1 << 0, - MSG_BT_YES = 1 << 1, - MSG_BT_NO = 1 << 2, - MSG_BT_CANCEL = 1 << 3 -}; +#include +using std::map; class XojMsgBox { @@ -36,7 +31,7 @@ public: static void setDefaultWindow(GtkWindow* win); static void showErrorToUser(GtkWindow* win, string msg); - static int showPluginMessage(string pluginName, string msg, int type, bool error = false); + static int showPluginMessage(string pluginName, string msg, map button, bool error = false); static int replaceFileQuestion(GtkWindow* win, string msg); static void showHelp(GtkWindow* win); }; From b8a720ddb05d50ffe5044ba54bdbb65ac6a8b0be Mon Sep 17 00:00:00 2001 From: Andreas Butti Date: Fri, 22 Feb 2019 16:26:14 +0100 Subject: [PATCH 4/4] Plugin handling --- plugins/Example/main.lua | 2 +- src/plugin/Plugin.cpp | 18 ++++++++++++++++-- src/plugin/Plugin.h | 11 +++++++++-- src/plugin/PluginController.cpp | 2 +- src/plugin/luapi_application.h | 17 ++++++++++++++--- 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/plugins/Example/main.lua b/plugins/Example/main.lua index 9090e7d9..f63a7486 100644 --- a/plugins/Example/main.lua +++ b/plugins/Example/main.lua @@ -6,7 +6,7 @@ var_dump = require "var_dump" function initUi() print("Hello from Example: Plugin initUi called\n"); - ref = app.registerUi({["menu"] = "Test123", ["callback"] = "exampleCallback"}); + ref = app.registerUi({["menu"] = "Test123", ["callback"] = "exampleCallback", ["accelerator"] = "t"}); print("Menu reference:"); var_dump(ref); diff --git a/src/plugin/Plugin.cpp b/src/plugin/Plugin.cpp index 93f2769c..26205481 100644 --- a/src/plugin/Plugin.cpp +++ b/src/plugin/Plugin.cpp @@ -119,7 +119,7 @@ void Plugin::registerToolbar() /** * Register all menu entries to the menu */ -void Plugin::registerMenu(GtkWidget* menu) +void Plugin::registerMenu(GtkWindow* mainWindow, GtkWidget* menu) { XOJ_CHECK_TYPE(Plugin); @@ -131,12 +131,23 @@ void Plugin::registerMenu(GtkWidget* menu) gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new()); + GtkAccelGroup* accelGroup = gtk_accel_group_new(); + for (MenuEntry* m : menuEntries) { GtkWidget* mi = gtk_menu_item_new_with_label(m->menu.c_str()); m->widget = mi; gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); + if (m->accelerator != "") + { + guint acceleratorKey = 0; + GdkModifierType mods = (GdkModifierType)0; + gtk_accelerator_parse(m->accelerator.c_str(), &acceleratorKey, &mods); + + gtk_widget_add_accelerator(mi, "activate", accelGroup, acceleratorKey, mods, GTK_ACCEL_VISIBLE); + } + g_signal_connect(mi, "activate", G_CALLBACK( +[](GtkWidget* bt, MenuEntry* me) { @@ -144,6 +155,8 @@ void Plugin::registerMenu(GtkWidget* menu) me->plugin->executeMenuEntry(me); }), m); } + + gtk_window_add_accel_group(GTK_WINDOW(mainWindow), accelGroup); } /** @@ -181,11 +194,12 @@ bool Plugin::isInInitUi() * * @return Internal ID, can e.g. be used to disable the menu */ -int Plugin::registerMenu(string menu, string callback) +int Plugin::registerMenu(string menu, string callback, string accelerator) { MenuEntry* m = new MenuEntry(this); m->menu = menu; m->callback = callback; + m->accelerator = accelerator; menuEntries.push_back(m); return menuEntries.size() - 1; diff --git a/src/plugin/Plugin.h b/src/plugin/Plugin.h index 95fa682b..18851800 100644 --- a/src/plugin/Plugin.h +++ b/src/plugin/Plugin.h @@ -58,6 +58,13 @@ public: * Callback function name */ string callback; + + /** + * Accelerator key + * + * See https://developer.gnome.org/gtk3/stable/gtk3-Keyboard-Accelerators.html#gtk-accelerator-parse + */ + string accelerator; }; class Plugin @@ -80,7 +87,7 @@ public: /** * Register all menu entries to the menu */ - void registerMenu(GtkWidget* menu); + void registerMenu(GtkWindow* mainWindow, GtkWidget* menu); /** * Execute menu entry @@ -102,7 +109,7 @@ public: * * @return Internal ID, can e.g. be used to disable the menu */ - int registerMenu(string menu, string callback); + int registerMenu(string menu, string callback, string accelerator); private: /** diff --git a/src/plugin/PluginController.cpp b/src/plugin/PluginController.cpp index c1a5e9f3..50b652fb 100644 --- a/src/plugin/PluginController.cpp +++ b/src/plugin/PluginController.cpp @@ -109,7 +109,7 @@ void PluginController::registerMenu() GtkWidget* menuPlugin = control->getWindow()->get("menuPlugin"); for (Plugin* p : this->plugins) { - p->registerMenu(menuPlugin); + p->registerMenu(control->getGtkWindow(), menuPlugin); } gtk_widget_show_all(menuPlugin); diff --git a/src/plugin/luapi_application.h b/src/plugin/luapi_application.h index 61895114..1c2e34bc 100644 --- a/src/plugin/luapi_application.h +++ b/src/plugin/luapi_application.h @@ -68,30 +68,41 @@ static int applib_registerUi(lua_State* L) // 'unpack' the table by putting the values onto // the stack first. Then convert those stack values // into an appropriate C type. + lua_getfield(L, 1, "accelerator"); lua_getfield(L, 1, "menu"); lua_getfield(L, 1, "callback"); // stack now has following: - // 1 = {"menu"="MenuName", callback="functionName"} + // 1 = {"menu"="MenuName", callback="functionName", accelerator="a"} + // -3 = "a" // -2 = "MenuName" // -1 = "functionName" + const char* accelerator = luaL_optstring(L, -3, NULL); const char* menu = luaL_optstring(L, -2, NULL); const char* callback = luaL_optstring(L, -1, NULL); if (callback == NULL) { luaL_error(L, "Missing callback function!"); } + if (menu == NULL) + { + menu = ""; + } + if (accelerator == NULL) + { + accelerator = ""; + } int menuId = -1; int toolbarId = -1; if (menu) { - menuId = plugin->registerMenu(menu, callback); + menuId = plugin->registerMenu(menu, callback, accelerator); } // Make sure to remove all vars which are put to the stack before! - lua_pop(L, 2); + lua_pop(L, 3); // Add return value to the Stack lua_createtable(L, 0, 2);