From 472f14c80350455cd492c867104941e884f74034 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Fri, 17 Feb 2017 18:56:18 +0100 Subject: Allow Lua action scripts to provide a button icon --- gtk2_ardour/ardour_ui.h | 1 + gtk2_ardour/ardour_ui_dependents.cc | 13 +++++++ gtk2_ardour/editor.cc | 1 - gtk2_ardour/luainstance.cc | 75 ++++++++++++++++++++++++++++++++----- gtk2_ardour/luainstance.h | 7 ++++ 5 files changed, 87 insertions(+), 10 deletions(-) (limited to 'gtk2_ardour') diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h index a0a8352d32..31fd2e1f65 100644 --- a/gtk2_ardour/ardour_ui.h +++ b/gtk2_ardour/ardour_ui.h @@ -904,6 +904,7 @@ private: void pre_release_dialog (); bool bind_lua_action_script (GdkEventButton*, int); + void update_action_script_btn (int i, const std::string&); }; #endif /* __ardour_gui_h__ */ diff --git a/gtk2_ardour/ardour_ui_dependents.cc b/gtk2_ardour/ardour_ui_dependents.cc index 6c0083291b..c39a44c451 100644 --- a/gtk2_ardour/ardour_ui_dependents.cc +++ b/gtk2_ardour/ardour_ui_dependents.cc @@ -304,6 +304,8 @@ ARDOUR_UI::setup_windows () main_vpacker.pack_start (status_bar_hpacker, false, false); #endif + LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::update_action_script_btn)); + for (int i = 0; i < 9; ++i) { std::string const a = string_compose (X_("script-action-%1"), i + 1); Glib::RefPtr act = ActionManager::get_action(X_("Editor"), a.c_str()); @@ -411,3 +413,14 @@ ARDOUR_UI::bind_lua_action_script (GdkEventButton*ev, int i) li->interactive_add (LuaScriptInfo::EditorAction, i); return true; } + +void +ARDOUR_UI::update_action_script_btn (int i, const std::string&) +{ + if (LuaInstance::instance()->lua_action_has_icon (i)) { + uintptr_t ii = i; + action_script_call_btn[i].set_icon (&LuaInstance::render_action_icon, (void*)ii); + } else { + action_script_call_btn[i].set_icon (0, 0); + } +} diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 4ebddd1367..75c9da4269 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -868,7 +868,6 @@ Editor::Editor () setup_fade_images (); - LuaInstance::instance(); // instantiate LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name)); instant_save (); diff --git a/gtk2_ardour/luainstance.cc b/gtk2_ardour/luainstance.cc index 01b311e91d..966715edc0 100644 --- a/gtk2_ardour/luainstance.cc +++ b/gtk2_ardour/luainstance.cc @@ -851,6 +851,7 @@ LuaInstance::LuaInstance () LuaInstance::~LuaInstance () { delete _lua_call_action; + delete _lua_render_icon; delete _lua_add_action; delete _lua_del_action; delete _lua_get_action; @@ -866,22 +867,28 @@ LuaInstance::init () { lua.do_command ( "function ScriptManager ()" - " local self = { scripts = {}, instances = {} }" + " local self = { scripts = {}, instances = {}, icons = {} }" "" " local remove = function (id)" " self.scripts[id] = nil" " self.instances[id] = nil" + " self.icons[id] = nil" " end" "" - " local addinternal = function (i, n, s, f, a)" + " local addinternal = function (i, n, s, f, c, a)" " assert(type(i) == 'number', 'id must be numeric')" " assert(type(n) == 'string', 'Name must be string')" " assert(type(s) == 'string', 'Script must be string')" " assert(type(f) == 'function', 'Factory is a not a function')" " assert(type(a) == 'table' or type(a) == 'nil', 'Given argument is invalid')" - " self.scripts[i] = { ['n'] = n, ['s'] = s, ['f'] = f, ['a'] = a }" + " self.scripts[i] = { ['n'] = n, ['s'] = s, ['f'] = f, ['a'] = a, ['c'] = c }" " local env = _ENV; env.f = nil env.debug = nil os.exit = nil require = nil dofile = nil loadfile = nil package = nil" " self.instances[i] = load (string.dump(f, true), nil, nil, env)(a)" + " if type(c) == 'function' then" + " self.icons[i] = load (string.dump(c, true), nil, nil, env)(a)" + " else" + " self.icons[i] = nil" + " end" " end" "" " local call = function (id)" @@ -895,17 +902,26 @@ LuaInstance::init () " collectgarbage()" " end" "" - " local add = function (i, n, s, b, a)" + " local icon = function (id, ...)" + " if type(self.icons[id]) == 'function' then" + " pcall (self.icons[id], ...)" + " end" + " collectgarbage()" + " end" + "" + " local add = function (i, n, s, b, c, a)" " assert(type(b) == 'string', 'ByteCode must be string')" - " load (b)()" // assigns f + " f = nil load (b)()" // assigns f + " icn = nil load (c)()" // may assign "icn" " assert(type(f) == 'string', 'Assigned ByteCode must be string')" - " addinternal (i, n, s, load(f), a)" + " addinternal (i, n, s, load(f), type(icn) ~= \"string\" or icn == '' or load(icn), a)" " end" "" " local get = function (id)" " if type(self.scripts[id]) == 'table' then" " return { ['name'] = self.scripts[id]['n']," " ['script'] = self.scripts[id]['s']," + " ['icon'] = type(self.scripts[id]['c']) == 'function'," " ['args'] = self.scripts[id]['a'] }" " end" " return nil" @@ -934,6 +950,8 @@ LuaInstance::init () " return rv;" " elseif type(value) == \"function\" then" " return rv .. string.format(\"%q\", string.dump(value, true))" + " elseif type(value) == \"boolean\" then" + " return rv .. tostring (value)" " else" " error('cannot save a ' .. type(value))" " end" @@ -947,6 +965,7 @@ LuaInstance::init () " local clear = function ()" " self.scripts = {}" " self.instances = {}" + " self.icons = {}" " collectgarbage()" " end" "" @@ -954,13 +973,13 @@ LuaInstance::init () " clear()" " load (state)()" " for i, s in pairs (scripts) do" - " addinternal (i, s['n'], s['s'], load(s['f']), s['a'])" + " addinternal (i, s['n'], s['s'], load(s['f']), type (s['c']) ~= \"string\" or s['c'] == '' or load (s['c']), s['a'])" " end" " collectgarbage()" " end" "" " return { call = call, add = add, remove = remove, get = get," - " restore = restore, save = save, clear = clear}" + " restore = restore, save = save, clear = clear, icon = icon}" " end" " " " manager = ScriptManager ()" @@ -978,6 +997,7 @@ LuaInstance::init () _lua_del_action = new luabridge::LuaRef(lua_mgr["remove"]); _lua_get_action = new luabridge::LuaRef(lua_mgr["get"]); _lua_call_action = new luabridge::LuaRef(lua_mgr["call"]); + _lua_render_icon = new luabridge::LuaRef(lua_mgr["icon"]); _lua_save = new luabridge::LuaRef(lua_mgr["save"]); _lua_load = new luabridge::LuaRef(lua_mgr["restore"]); _lua_clear = new luabridge::LuaRef(lua_mgr["clear"]); @@ -1184,6 +1204,23 @@ LuaInstance::call_action (const int id) } } +void +LuaInstance::render_action_icon (cairo_t* cr, int w, int h, uint32_t c, void* i) { + int ii = reinterpret_cast (i); + instance()->render_icon (ii, cr, w, h, c); +} + +void +LuaInstance::render_icon (int i, cairo_t* cr, int w, int h, uint32_t clr) +{ + Cairo::Context ctx (cr); + try { + (*_lua_render_icon)(i + 1, (Cairo::Context *)&ctx, w, h, clr); + } catch (luabridge::LuaException const& e) { + cerr << "LuaException:" << e.what () << endl; + } +} + bool LuaInstance::set_lua_action ( const int id, @@ -1196,12 +1233,13 @@ LuaInstance::set_lua_action ( // get bytcode of factory-function in a sandbox // (don't allow scripts to interfere) const std::string& bytecode = LuaScripting::get_factory_bytecode (script); + const std::string& iconfunc = LuaScripting::get_factory_bytecode (script, "icon", "icn"); luabridge::LuaRef tbl_arg (luabridge::newTable(L)); for (LuaScriptParamList::const_iterator i = args.begin(); i != args.end(); ++i) { if ((*i)->optional && !(*i)->is_set) { continue; } tbl_arg[(*i)->name] = (*i)->value; } - (*_lua_add_action)(id + 1, name, script, bytecode, tbl_arg); + (*_lua_add_action)(id + 1, name, script, bytecode, iconfunc, tbl_arg); ActionChanged (id, name); /* EMIT SIGNAL */ } catch (luabridge::LuaException const& e) { cerr << "LuaException:" << e.what () << endl; @@ -1258,6 +1296,23 @@ LuaInstance::lua_action_names () return rv; } +bool +LuaInstance::lua_action_has_icon (const int id) +{ + try { + luabridge::LuaRef ref ((*_lua_get_action)(id + 1)); + if (ref.isNil()) { + return false; + } + if (ref["icon"].isBoolean()) { + return ref["icon"].cast(); + } + } catch (luabridge::LuaException const& e) { + cerr << "LuaException:" << e.what () << endl; + } + return false; +} + bool LuaInstance::lua_action (const int id, std::string& name, std::string& script, LuaScriptParamList& args) { @@ -1570,6 +1625,8 @@ LuaCallback::init (void) " return rv;" " elseif type(value) == \"function\" then" " return rv .. string.format(\"%q\", string.dump(value, true))" + " elseif type(value) == \"boolean\" then" + " return rv .. tostring (value)" " else" " error('cannot save a ' .. type(value))" " end" diff --git a/gtk2_ardour/luainstance.h b/gtk2_ardour/luainstance.h index cad533e753..4d3d0b1973 100644 --- a/gtk2_ardour/luainstance.h +++ b/gtk2_ardour/luainstance.h @@ -3,6 +3,8 @@ #include +#include + #include "pbd/id.h" #include "pbd/signals.h" #include "pbd/xml++.h" @@ -86,6 +88,8 @@ public: static void register_hooks (lua_State* L); static void bind_cairo (lua_State* L); + static void render_action_icon (cairo_t* cr, int w, int h, uint32_t c, void* i); + void set_session (ARDOUR::Session* s); int set_state (const XMLNode&); @@ -96,12 +100,14 @@ public: /* actions */ void call_action (const int); + void render_icon (int i, cairo_t*, int, int, uint32_t); bool set_lua_action (const int, const std::string&, const std::string&, const ARDOUR::LuaScriptParamList&); bool remove_lua_action (const int); bool lua_action_name (const int, std::string&); std::vector lua_action_names (); bool lua_action (const int, std::string&, std::string&, ARDOUR::LuaScriptParamList&); + bool lua_action_has_icon (const int); sigc::signal ActionChanged; /* callbacks */ @@ -125,6 +131,7 @@ private: LuaState lua; luabridge::LuaRef * _lua_call_action; + luabridge::LuaRef * _lua_render_icon; luabridge::LuaRef * _lua_add_action; luabridge::LuaRef * _lua_del_action; luabridge::LuaRef * _lua_get_action; -- cgit v1.2.3