2 * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include "gtkmm2ext/gui_thread.h"
20 #include "gtkmm2ext/utils.h"
22 #include "ardour/session.h"
24 #include "LuaBridge/LuaBridge.h"
26 #include "lua_script_manager.h"
27 #include "luawindow.h"
28 #include "script_selector.h"
33 using namespace ARDOUR;
35 LuaScriptManager::LuaScriptManager ()
36 : ArdourWindow (_("Script Manager"))
37 , _a_set_button (_("Add/Set"))
38 , _a_del_button (_("Remove"))
39 , _a_edit_button (_("Edit"))
40 , _a_call_button (_("Call"))
41 , _c_add_button (_("New Hook"))
42 , _c_del_button (_("Remove"))
43 , _s_add_button (_("Load"))
44 , _s_del_button (_("Remove"))
46 /* action script page */
47 _a_store = ListStore::create (_a_model);
48 _a_view.set_model (_a_store);
49 _a_view.append_column (_("Action"), _a_model.action);
50 _a_view.append_column (_("Name"), _a_model.name);
51 _a_view.get_column(0)->set_resizable (true);
52 _a_view.get_column(0)->set_expand (true);
53 _a_view.get_column(1)->set_resizable (true);
54 _a_view.get_column(1)->set_expand (true);
59 Gtk::HBox* edit_box = manage (new Gtk::HBox);
60 edit_box->set_spacing(3);
62 edit_box->pack_start (_a_set_button, true, true);
63 edit_box->pack_start (_a_del_button, true, true);
64 edit_box->pack_start (_a_edit_button, true, true);
65 edit_box->pack_start (_a_call_button, true, true);
67 _a_set_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::set_action_btn_clicked));
68 _a_del_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::del_action_btn_clicked));
69 _a_edit_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::edit_action_btn_clicked));
70 _a_call_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::call_action_btn_clicked));
71 _a_view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &LuaScriptManager::action_selection_changed));
73 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &LuaScriptManager::set_action_script_name));
74 LuaInstance::instance()->SlotChanged.connect (sigc::mem_fun (*this, &LuaScriptManager::set_callback_script_name));
76 f = manage (new Frame (_("Description")));
77 doc = manage (new Label (
78 _("Action Scripts are user initiated actions (menu, shortcuts, toolbar-button) for batch processing or customized tasks.")
80 doc->set_padding (5, 5);
84 Gtk::VBox *vbox = manage (new VBox());
85 vbox->pack_start (_a_view, false, false);
86 vbox->pack_end (*edit_box, false, false);
87 vbox->pack_end (*f, false, false);
90 pages.pages ().push_back (Notebook_Helpers::TabElem (*vbox, "Action Scripts"));
92 /* action hooks page */
94 _c_store = ListStore::create (_c_model);
95 _c_view.set_model (_c_store);
96 _c_view.append_column (_("Name"), _c_model.name);
97 _c_view.append_column (_("Signal(s)"), _c_model.signals);
98 _c_view.get_column(0)->set_resizable (true);
99 _c_view.get_column(0)->set_expand (true);
100 _c_view.get_column(1)->set_resizable (true);
101 _c_view.get_column(1)->set_expand (true);
102 Gtk::CellRendererText* r = dynamic_cast<Gtk::CellRendererText*>(_c_view.get_column_cell_renderer (1));
103 r->property_ellipsize () = Pango::ELLIPSIZE_MIDDLE;
105 edit_box = manage (new Gtk::HBox);
106 edit_box->set_spacing(3);
107 edit_box->pack_start (_c_add_button, true, true);
108 edit_box->pack_start (_c_del_button, true, true);
110 _c_add_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::add_callback_btn_clicked));
111 _c_del_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::del_callback_btn_clicked));
112 _c_view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &LuaScriptManager::callback_selection_changed));
114 f = manage (new Frame (_("Description")));
115 doc = manage (new Label (
116 _("Lua action hooks are event-triggered callbacks for the Editor/Mixer GUI. Once a script is registered it is automatically triggered by events to perform some task.")
118 doc->set_padding (5, 5);
119 doc->set_line_wrap();
122 vbox = manage (new VBox());
123 vbox->pack_start (_c_view, false, false);
124 vbox->pack_end (*edit_box, false, false);
125 vbox->pack_end (*f, false, false);
128 pages.pages ().push_back (Notebook_Helpers::TabElem (*vbox, "Action Hooks"));
130 /* session script page */
132 _s_store = ListStore::create (_s_model);
133 _s_view.set_model (_s_store);
134 _s_view.append_column (_("Name"), _s_model.name);
135 _s_view.get_column(0)->set_resizable (true);
136 _s_view.get_column(0)->set_expand (true);
138 edit_box = manage (new Gtk::HBox);
139 edit_box->set_spacing(3);
140 edit_box->pack_start (_s_add_button, true, true);
141 edit_box->pack_start (_s_del_button, true, true);
143 _s_add_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::add_sess_btn_clicked));
144 _s_del_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::del_sess_btn_clicked));
145 _s_view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &LuaScriptManager::session_script_selection_changed));
147 f = manage (new Frame (_("Description")));
148 doc = manage (new Label (
149 _("Lua session scripts are loaded into processing engine and run in realtime. They are called periodically at the start of every audio cycle in the realtime process context before any processing takes place.")
151 doc->set_padding (5, 5);
152 doc->set_line_wrap();
155 vbox = manage (new VBox());
156 vbox->pack_start (_s_view, false, false);
157 vbox->pack_end (*edit_box, false, false);
158 vbox->pack_end (*f, false, false);
161 pages.pages ().push_back (Notebook_Helpers::TabElem (*vbox, "Session Scripts"));
170 setup_session_scripts ();
172 action_selection_changed ();
173 callback_selection_changed ();
174 session_script_selection_changed ();
178 LuaScriptManager::set_session (ARDOUR::Session *s)
180 ArdourWindow::set_session (s);
181 setup_session_scripts ();
186 _session->LuaScriptsChanged.connect (_session_script_connection, invalidator (*this), boost::bind (&LuaScriptManager::setup_session_scripts, this), gui_context());
187 setup_session_scripts ();
191 LuaScriptManager::session_going_away ()
193 ArdourWindow::session_going_away ();
194 _session_script_connection.disconnect ();
199 LuaScriptManager::setup_actions ()
201 LuaInstance *li = LuaInstance::instance();
202 for (int i = 0; i < 9; ++i) {
204 TreeModel::Row r = *_a_store->append ();
206 r[_a_model.action] = string_compose (_("Action %1"), i + 1);
207 if (li->lua_action_name (i, name)) {
208 r[_a_model.name] = name;
209 r[_a_model.enabled] = true;
211 r[_a_model.name] = _("Unset");
212 r[_a_model.enabled] = false;
218 LuaScriptManager::action_selection_changed ()
220 TreeModel::Row row = *(_a_view.get_selection()->get_selected());
222 _a_set_button.set_sensitive (true);
225 _a_set_button.set_sensitive (false);
228 if (row && row[_a_model.enabled]) {
229 _a_del_button.set_sensitive (true);
230 _a_edit_button.set_sensitive (true);
231 _a_call_button.set_sensitive (true);
233 _a_del_button.set_sensitive (false);
234 _a_edit_button.set_sensitive (false);
235 _a_call_button.set_sensitive (false);
240 LuaScriptManager::set_action_btn_clicked ()
242 TreeModel::Row row = *(_a_view.get_selection()->get_selected());
244 LuaInstance *li = LuaInstance::instance();
245 li->interactive_add (LuaScriptInfo::EditorAction, row[_a_model.id]);
249 LuaScriptManager::del_action_btn_clicked ()
251 TreeModel::Row row = *(_a_view.get_selection()->get_selected());
253 LuaInstance *li = LuaInstance::instance();
254 if (!li->remove_lua_action (row[_a_model.id])) {
260 LuaScriptManager::call_action_btn_clicked ()
262 TreeModel::Row row = *(_a_view.get_selection()->get_selected());
263 assert (row && row[_a_model.enabled]);
264 LuaInstance *li = LuaInstance::instance();
265 li->call_action (row[_a_model.id]);
269 LuaScriptManager::edit_action_btn_clicked ()
271 TreeModel::Row row = *(_a_view.get_selection()->get_selected());
273 int id = row[_a_model.id];
274 LuaInstance *li = LuaInstance::instance();
275 std::string name, script;
276 LuaScriptParamList args;
277 if (!li->lua_action (id, name, script, args)) {
280 LuaWindow::instance()->edit_script (name, script);
284 LuaScriptManager::set_action_script_name (int i, const std::string& name)
286 typedef Gtk::TreeModel::Children type_children;
287 type_children children = _a_store->children();
288 for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter) {
289 Gtk::TreeModel::Row row = *iter;
290 if (row[_a_model.id] == i) {
292 row[_a_model.enabled] = false;
293 row[_a_model.name] = _("Unset");
295 row[_a_model.enabled] = true;
296 row[_a_model.name] = name;
301 action_selection_changed ();
306 LuaScriptManager::setup_callbacks ()
308 LuaInstance *li = LuaInstance::instance();
309 std::vector<PBD::ID> ids = li->lua_slots();
310 for (std::vector<PBD::ID>::const_iterator i = ids.begin(); i != ids.end(); ++i) {
314 LuaScriptParamList lsp;
315 if (li->lua_slot (*i, name, script, ah, lsp)) {
316 set_callback_script_name (*i, name, ah);
322 LuaScriptManager::callback_selection_changed ()
324 TreeModel::Row row = *(_c_view.get_selection()->get_selected());
326 _c_del_button.set_sensitive (true);
328 _c_del_button.set_sensitive (false);
333 LuaScriptManager::add_callback_btn_clicked ()
335 LuaInstance *li = LuaInstance::instance();
336 li->interactive_add (LuaScriptInfo::EditorHook, -1);
340 LuaScriptManager::del_callback_btn_clicked ()
342 TreeModel::Row row = *(_c_view.get_selection()->get_selected());
344 LuaInstance *li = LuaInstance::instance();
345 if (!li->unregister_lua_slot (row[_c_model.id])) {
351 LuaScriptManager::set_callback_script_name (PBD::ID id, const std::string& name, const ActionHook& ah)
354 typedef Gtk::TreeModel::Children type_children;
355 type_children children = _c_store->children();
356 for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter) {
357 Gtk::TreeModel::Row row = *iter;
358 PBD::ID i = row[_c_model.id];
360 _c_store->erase (iter);
365 TreeModel::Row r = *_c_store->append ();
367 r[_c_model.name] = name;
369 for (uint32_t i = 0; i < LuaSignal::LAST_SIGNAL; ++i) {
371 if (!sig.empty()) sig += ", ";
372 sig += enum2str (LuaSignal::LuaSignal (i));
375 r[_c_model.signals] = sig;
377 callback_selection_changed ();
382 LuaScriptManager::setup_session_scripts ()
388 std::vector<std::string> reg = _session->registered_lua_functions ();
389 for (std::vector<string>::const_iterator i = reg.begin(); i != reg.end(); ++i) {
390 TreeModel::Row r = *_s_store->append ();
391 r[_s_model.name] = *i;
393 session_script_selection_changed ();
397 LuaScriptManager::session_script_selection_changed ()
400 _s_del_button.set_sensitive (false);
401 _s_add_button.set_sensitive (false);
404 TreeModel::Row row = *(_s_view.get_selection()->get_selected());
406 _s_del_button.set_sensitive (true);
408 _s_del_button.set_sensitive (false);
410 _s_add_button.set_sensitive (true);
414 LuaScriptManager::add_sess_btn_clicked ()
419 LuaInstance *li = LuaInstance::instance();
420 li->interactive_add (LuaScriptInfo::Session, -1);
424 LuaScriptManager::del_sess_btn_clicked ()
427 TreeModel::Row row = *(_s_view.get_selection()->get_selected());
428 const std::string& name = row[_s_model.name];
430 _session->unregister_lua_function (name);
431 } catch (luabridge::LuaException const& e) {
432 string msg = string_compose (_("Session script '%1' removal failed: %2"), name, e.what ());
433 MessageDialog am (msg);