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 <gtkmm/box.h>
20 #include <gtkmm/frame.h>
21 #include <gtkmm/messagedialog.h>
23 #include "gtkmm2ext/gui_thread.h"
24 #include "gtkmm2ext/utils.h"
26 #include "ardour/session.h"
28 #include "LuaBridge/LuaBridge.h"
30 #include "ardour_ui.h"
31 #include "lua_script_manager.h"
32 #include "luawindow.h"
33 #include "script_selector.h"
38 using namespace ARDOUR;
40 LuaScriptManager::LuaScriptManager ()
41 : ArdourWindow (_("Script Manager"))
42 , _a_set_button (_("Add/Set"))
43 , _a_del_button (_("Remove"))
44 , _a_edit_button (_("Edit"))
45 , _a_call_button (_("Call"))
46 , _c_add_button (_("New Hook"))
47 , _c_del_button (_("Remove"))
48 , _s_add_button (_("Load"))
49 , _s_del_button (_("Remove"))
51 /* action script page */
52 _a_store = ListStore::create (_a_model);
53 _a_view.set_model (_a_store);
54 _a_view.append_column (_("Action"), _a_model.action);
55 _a_view.append_column (_("Name"), _a_model.name);
56 _a_view.get_column(0)->set_resizable (true);
57 _a_view.get_column(0)->set_expand (true);
58 _a_view.get_column(1)->set_resizable (true);
59 _a_view.get_column(1)->set_expand (true);
64 Gtk::HBox* edit_box = manage (new Gtk::HBox);
65 edit_box->set_spacing(3);
67 edit_box->pack_start (_a_set_button, true, true);
68 edit_box->pack_start (_a_del_button, true, true);
69 edit_box->pack_start (_a_edit_button, true, true);
70 edit_box->pack_start (_a_call_button, true, true);
72 _a_set_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::set_action_btn_clicked));
73 _a_del_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::del_action_btn_clicked));
74 _a_edit_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::edit_action_btn_clicked));
75 _a_call_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::call_action_btn_clicked));
76 _a_view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &LuaScriptManager::action_selection_changed));
78 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &LuaScriptManager::set_action_script_name));
79 LuaInstance::instance()->SlotChanged.connect (sigc::mem_fun (*this, &LuaScriptManager::set_callback_script_name));
81 f = manage (new Frame (_("Description")));
82 doc = manage (new Label (
83 _("Action Scripts are user initiated actions (menu, shortcuts, toolbar-button) for batch processing or customized tasks.")
85 doc->set_padding (5, 5);
89 Gtk::VBox *vbox = manage (new VBox());
90 vbox->pack_start (_a_view, false, false);
91 vbox->pack_end (*edit_box, false, false);
92 vbox->pack_end (*f, false, false);
95 pages.pages ().push_back (Notebook_Helpers::TabElem (*vbox, "Action Scripts"));
97 /* action hooks page */
99 _c_store = ListStore::create (_c_model);
100 _c_view.set_model (_c_store);
101 _c_view.append_column (_("Name"), _c_model.name);
102 _c_view.append_column (_("Signal(s)"), _c_model.signals);
103 _c_view.get_column(0)->set_resizable (true);
104 _c_view.get_column(0)->set_expand (true);
105 _c_view.get_column(1)->set_resizable (true);
106 _c_view.get_column(1)->set_expand (true);
107 Gtk::CellRendererText* r = dynamic_cast<Gtk::CellRendererText*>(_c_view.get_column_cell_renderer (1));
108 r->property_ellipsize () = Pango::ELLIPSIZE_MIDDLE;
110 edit_box = manage (new Gtk::HBox);
111 edit_box->set_spacing(3);
112 edit_box->pack_start (_c_add_button, true, true);
113 edit_box->pack_start (_c_del_button, true, true);
115 _c_add_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::add_callback_btn_clicked));
116 _c_del_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::del_callback_btn_clicked));
117 _c_view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &LuaScriptManager::callback_selection_changed));
119 f = manage (new Frame (_("Description")));
120 doc = manage (new Label (
121 _("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.")
123 doc->set_padding (5, 5);
124 doc->set_line_wrap();
127 vbox = manage (new VBox());
128 vbox->pack_start (_c_view, false, false);
129 vbox->pack_end (*edit_box, false, false);
130 vbox->pack_end (*f, false, false);
133 pages.pages ().push_back (Notebook_Helpers::TabElem (*vbox, "Action Hooks"));
135 /* session script page */
137 _s_store = ListStore::create (_s_model);
138 _s_view.set_model (_s_store);
139 _s_view.append_column (_("Name"), _s_model.name);
140 _s_view.get_column(0)->set_resizable (true);
141 _s_view.get_column(0)->set_expand (true);
143 edit_box = manage (new Gtk::HBox);
144 edit_box->set_spacing(3);
145 edit_box->pack_start (_s_add_button, true, true);
146 edit_box->pack_start (_s_del_button, true, true);
148 _s_add_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::add_sess_btn_clicked));
149 _s_del_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::del_sess_btn_clicked));
150 _s_view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &LuaScriptManager::session_script_selection_changed));
152 f = manage (new Frame (_("Description")));
153 doc = manage (new Label (
154 _("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.")
156 doc->set_padding (5, 5);
157 doc->set_line_wrap();
160 vbox = manage (new VBox());
161 vbox->pack_start (_s_view, false, false);
162 vbox->pack_end (*edit_box, false, false);
163 vbox->pack_end (*f, false, false);
166 pages.pages ().push_back (Notebook_Helpers::TabElem (*vbox, "Session Scripts"));
175 setup_session_scripts ();
177 action_selection_changed ();
178 callback_selection_changed ();
179 session_script_selection_changed ();
183 LuaScriptManager::set_session (ARDOUR::Session *s)
185 ArdourWindow::set_session (s);
186 setup_session_scripts ();
191 _session->LuaScriptsChanged.connect (_session_script_connection, invalidator (*this), boost::bind (&LuaScriptManager::setup_session_scripts, this), gui_context());
192 setup_session_scripts ();
196 LuaScriptManager::session_going_away ()
198 ArdourWindow::session_going_away ();
199 _session_script_connection.disconnect ();
204 LuaScriptManager::setup_actions ()
206 LuaInstance *li = LuaInstance::instance();
207 for (int i = 0; i < MAX_LUA_ACTION_SCRIPTS; ++i) {
209 TreeModel::Row r = *_a_store->append ();
211 r[_a_model.action] = string_compose (_("Action %1"), i + 1);
212 if (li->lua_action_name (i, name)) {
213 r[_a_model.name] = name;
214 r[_a_model.enabled] = true;
216 r[_a_model.name] = _("Unset");
217 r[_a_model.enabled] = false;
223 LuaScriptManager::action_selection_changed ()
225 TreeModel::Row row = *(_a_view.get_selection()->get_selected());
227 _a_set_button.set_sensitive (true);
230 _a_set_button.set_sensitive (false);
233 if (row && row[_a_model.enabled]) {
234 _a_del_button.set_sensitive (true);
235 _a_edit_button.set_sensitive (true);
236 _a_call_button.set_sensitive (true);
238 _a_del_button.set_sensitive (false);
239 _a_edit_button.set_sensitive (false);
240 _a_call_button.set_sensitive (false);
245 LuaScriptManager::set_action_btn_clicked ()
247 TreeModel::Row row = *(_a_view.get_selection()->get_selected());
249 LuaInstance *li = LuaInstance::instance();
250 li->interactive_add (LuaScriptInfo::EditorAction, row[_a_model.id]);
254 LuaScriptManager::del_action_btn_clicked ()
256 TreeModel::Row row = *(_a_view.get_selection()->get_selected());
258 LuaInstance *li = LuaInstance::instance();
259 if (!li->remove_lua_action (row[_a_model.id])) {
265 LuaScriptManager::call_action_btn_clicked ()
267 TreeModel::Row row = *(_a_view.get_selection()->get_selected());
268 assert (row && row[_a_model.enabled]);
269 LuaInstance *li = LuaInstance::instance();
270 li->call_action (row[_a_model.id]);
274 LuaScriptManager::edit_action_btn_clicked ()
276 TreeModel::Row row = *(_a_view.get_selection()->get_selected());
278 int id = row[_a_model.id];
279 LuaInstance *li = LuaInstance::instance();
280 std::string name, script;
281 LuaScriptParamList args;
282 if (!li->lua_action (id, name, script, args)) {
285 LuaWindow::instance()->edit_script (name, script);
289 LuaScriptManager::set_action_script_name (int i, const std::string& name)
291 typedef Gtk::TreeModel::Children type_children;
292 type_children children = _a_store->children();
293 for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter) {
294 Gtk::TreeModel::Row row = *iter;
295 if (row[_a_model.id] == i) {
297 row[_a_model.enabled] = false;
298 row[_a_model.name] = _("Unset");
300 row[_a_model.enabled] = true;
301 row[_a_model.name] = name;
306 action_selection_changed ();
311 LuaScriptManager::setup_callbacks ()
313 LuaInstance *li = LuaInstance::instance();
314 std::vector<PBD::ID> ids = li->lua_slots();
315 for (std::vector<PBD::ID>::const_iterator i = ids.begin(); i != ids.end(); ++i) {
319 LuaScriptParamList lsp;
320 if (li->lua_slot (*i, name, script, ah, lsp)) {
321 set_callback_script_name (*i, name, ah);
327 LuaScriptManager::callback_selection_changed ()
329 TreeModel::Row row = *(_c_view.get_selection()->get_selected());
331 _c_del_button.set_sensitive (true);
333 _c_del_button.set_sensitive (false);
338 LuaScriptManager::add_callback_btn_clicked ()
340 LuaInstance *li = LuaInstance::instance();
341 li->interactive_add (LuaScriptInfo::EditorHook, -1);
345 LuaScriptManager::del_callback_btn_clicked ()
347 TreeModel::Row row = *(_c_view.get_selection()->get_selected());
349 LuaInstance *li = LuaInstance::instance();
350 if (!li->unregister_lua_slot (row[_c_model.id])) {
356 LuaScriptManager::set_callback_script_name (PBD::ID id, const std::string& name, const ActionHook& ah)
359 typedef Gtk::TreeModel::Children type_children;
360 type_children children = _c_store->children();
361 for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter) {
362 Gtk::TreeModel::Row row = *iter;
363 PBD::ID i = row[_c_model.id];
365 _c_store->erase (iter);
370 TreeModel::Row r = *_c_store->append ();
372 r[_c_model.name] = name;
374 for (uint32_t i = 0; i < LuaSignal::LAST_SIGNAL; ++i) {
376 if (!sig.empty()) sig += ", ";
377 sig += enum2str (LuaSignal::LuaSignal (i));
380 r[_c_model.signals] = sig;
382 callback_selection_changed ();
387 LuaScriptManager::setup_session_scripts ()
393 std::vector<std::string> reg = _session->registered_lua_functions ();
394 for (std::vector<string>::const_iterator i = reg.begin(); i != reg.end(); ++i) {
395 TreeModel::Row r = *_s_store->append ();
396 r[_s_model.name] = *i;
398 session_script_selection_changed ();
402 LuaScriptManager::session_script_selection_changed ()
405 _s_del_button.set_sensitive (false);
406 _s_add_button.set_sensitive (false);
409 TreeModel::Row row = *(_s_view.get_selection()->get_selected());
411 _s_del_button.set_sensitive (true);
413 _s_del_button.set_sensitive (false);
415 _s_add_button.set_sensitive (true);
419 LuaScriptManager::add_sess_btn_clicked ()
424 LuaInstance *li = LuaInstance::instance();
425 li->interactive_add (LuaScriptInfo::Session, -1);
429 LuaScriptManager::del_sess_btn_clicked ()
432 TreeModel::Row row = *(_s_view.get_selection()->get_selected());
433 const std::string& name = row[_s_model.name];
435 _session->unregister_lua_function (name);
436 } catch (luabridge::LuaException const& e) {
437 string msg = string_compose (_("Session script '%1' removal failed: %2"), name, e.what ());
438 MessageDialog am (msg);