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 "script_selector.h"
32 using namespace ARDOUR;
34 LuaScriptManager::LuaScriptManager ()
35 : ArdourWindow (_("Script Manager"))
36 , _a_set_button (_("Add/Set"))
37 , _a_del_button (_("Remove"))
38 , _a_edit_button (_("Edit"))
39 , _a_call_button (_("Call"))
40 , _c_add_button (_("New Hook"))
41 , _c_del_button (_("Remove"))
42 , _s_add_button (_("Load"))
43 , _s_del_button (_("Remove"))
45 /* action script page */
46 _a_store = ListStore::create (_a_model);
47 _a_view.set_model (_a_store);
48 _a_view.append_column (_("Action"), _a_model.action);
49 _a_view.append_column (_("Name"), _a_model.name);
50 _a_view.get_column(0)->set_resizable (true);
51 _a_view.get_column(0)->set_expand (true);
52 _a_view.get_column(1)->set_resizable (true);
53 _a_view.get_column(1)->set_expand (true);
55 Gtk::HBox* edit_box = manage (new Gtk::HBox);
56 edit_box->set_spacing(3);
58 edit_box->pack_start (_a_set_button, true, true);
59 edit_box->pack_start (_a_del_button, true, true);
60 edit_box->pack_start (_a_edit_button, true, true);
61 edit_box->pack_start (_a_call_button, true, true);
63 _a_set_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::set_action_btn_clicked));
64 _a_del_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::del_action_btn_clicked));
65 _a_edit_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::edit_action_btn_clicked));
66 _a_call_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::call_action_btn_clicked));
67 _a_view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &LuaScriptManager::action_selection_changed));
69 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &LuaScriptManager::set_action_script_name));
70 LuaInstance::instance()->SlotChanged.connect (sigc::mem_fun (*this, &LuaScriptManager::set_callback_script_name));
72 Gtk::VBox *vbox = manage (new VBox());
73 vbox->pack_start (_a_view, false, false);
74 vbox->pack_end (*edit_box, false, false);
77 pages.pages ().push_back (Notebook_Helpers::TabElem (*vbox, "Action Scripts"));
79 /* action hooks page */
81 _c_store = ListStore::create (_c_model);
82 _c_view.set_model (_c_store);
83 _c_view.append_column (_("Name"), _c_model.name);
84 _c_view.append_column (_("Signal(s)"), _c_model.signals);
85 _c_view.get_column(0)->set_resizable (true);
86 _c_view.get_column(0)->set_expand (true);
87 _c_view.get_column(1)->set_resizable (true);
88 _c_view.get_column(1)->set_expand (true);
89 Gtk::CellRendererText* r = dynamic_cast<Gtk::CellRendererText*>(_c_view.get_column_cell_renderer (1));
90 r->property_ellipsize () = Pango::ELLIPSIZE_MIDDLE;
92 edit_box = manage (new Gtk::HBox);
93 edit_box->set_spacing(3);
94 edit_box->pack_start (_c_add_button, true, true);
95 edit_box->pack_start (_c_del_button, true, true);
97 _c_add_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::add_callback_btn_clicked));
98 _c_del_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::del_callback_btn_clicked));
99 _c_view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &LuaScriptManager::callback_selection_changed));
101 vbox = manage (new VBox());
102 vbox->pack_start (_c_view, false, false);
103 vbox->pack_end (*edit_box, false, false);
106 pages.pages ().push_back (Notebook_Helpers::TabElem (*vbox, "Action Hooks"));
108 /* session script page */
110 _s_store = ListStore::create (_s_model);
111 _s_view.set_model (_s_store);
112 _s_view.append_column (_("Name"), _s_model.name);
113 _s_view.get_column(0)->set_resizable (true);
114 _s_view.get_column(0)->set_expand (true);
116 edit_box = manage (new Gtk::HBox);
117 edit_box->set_spacing(3);
118 edit_box->pack_start (_s_add_button, true, true);
119 edit_box->pack_start (_s_del_button, true, true);
121 _s_add_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::add_sess_btn_clicked));
122 _s_del_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::del_sess_btn_clicked));
123 _s_view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &LuaScriptManager::session_script_selection_changed));
125 vbox = manage (new VBox());
126 vbox->pack_start (_s_view, false, false);
127 vbox->pack_end (*edit_box, false, false);
130 pages.pages ().push_back (Notebook_Helpers::TabElem (*vbox, "Session Scripts"));
139 setup_session_scripts ();
141 action_selection_changed ();
142 callback_selection_changed ();
143 session_script_selection_changed ();
147 LuaScriptManager::set_session (ARDOUR::Session *s)
149 ArdourWindow::set_session (s);
150 setup_session_scripts ();
155 _session->LuaScriptsChanged.connect (_session_script_connection, invalidator (*this), boost::bind (&LuaScriptManager::setup_session_scripts, this), gui_context());
156 setup_session_scripts ();
160 LuaScriptManager::session_going_away ()
162 ArdourWindow::session_going_away ();
163 _session_script_connection.disconnect ();
168 LuaScriptManager::setup_actions ()
170 LuaInstance *li = LuaInstance::instance();
171 for (int i = 0; i < 9; ++i) {
173 TreeModel::Row r = *_a_store->append ();
175 r[_a_model.action] = string_compose (_("Action %1"), i + 1);
176 if (li->lua_action_name (i, name)) {
177 r[_a_model.name] = name;
178 r[_a_model.enabled] = true;
180 r[_a_model.name] = _("Unset");
181 r[_a_model.enabled] = false;
187 LuaScriptManager::action_selection_changed ()
189 TreeModel::Row row = *(_a_view.get_selection()->get_selected());
191 _a_set_button.set_sensitive (true);
194 _a_set_button.set_sensitive (false);
197 if (row && row[_a_model.enabled]) {
198 _a_del_button.set_sensitive (true);
199 _a_edit_button.set_sensitive (false); // TODO
200 _a_call_button.set_sensitive (true);
202 _a_del_button.set_sensitive (false);
203 _a_edit_button.set_sensitive (false);
204 _a_call_button.set_sensitive (false);
209 LuaScriptManager::set_action_btn_clicked ()
211 TreeModel::Row row = *(_a_view.get_selection()->get_selected());
213 LuaInstance *li = LuaInstance::instance();
214 li->interactive_add (LuaScriptInfo::EditorAction, row[_a_model.id]);
218 LuaScriptManager::del_action_btn_clicked ()
220 TreeModel::Row row = *(_a_view.get_selection()->get_selected());
222 LuaInstance *li = LuaInstance::instance();
223 if (!li->remove_lua_action (row[_a_model.id])) {
229 LuaScriptManager::call_action_btn_clicked ()
231 TreeModel::Row row = *(_a_view.get_selection()->get_selected());
232 assert (row && row[_a_model.enabled]);
233 LuaInstance *li = LuaInstance::instance();
234 li->call_action (row[_a_model.id]);
238 LuaScriptManager::edit_action_btn_clicked ()
240 TreeModel::Row row = *(_a_view.get_selection()->get_selected());
242 int id = row[_a_model.id];
243 LuaInstance *li = LuaInstance::instance();
244 std::string name, script;
245 LuaScriptParamList args;
246 if (!li->lua_action (id, name, script, args)) {
250 // TODO text-editor window, update script directly
252 if (!LuaScripting::try_compile (script, args)) {
253 // compilation failed, keep editing
257 if (li->set_lua_action (id, name, script, args)) {
260 // load failed, keep editing..
262 action_selection_changed ();
266 LuaScriptManager::set_action_script_name (int i, const std::string& name)
268 typedef Gtk::TreeModel::Children type_children;
269 type_children children = _a_store->children();
270 for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter) {
271 Gtk::TreeModel::Row row = *iter;
272 if (row[_a_model.id] == i) {
274 row[_a_model.enabled] = false;
275 row[_a_model.name] = _("Unset");
277 row[_a_model.enabled] = true;
278 row[_a_model.name] = name;
283 action_selection_changed ();
288 LuaScriptManager::setup_callbacks ()
290 LuaInstance *li = LuaInstance::instance();
291 std::vector<PBD::ID> ids = li->lua_slots();
292 for (std::vector<PBD::ID>::const_iterator i = ids.begin(); i != ids.end(); ++i) {
296 LuaScriptParamList lsp;
297 if (li->lua_slot (*i, name, script, ah, lsp)) {
298 set_callback_script_name (*i, name, ah);
304 LuaScriptManager::callback_selection_changed ()
306 TreeModel::Row row = *(_c_view.get_selection()->get_selected());
308 _c_del_button.set_sensitive (true);
310 _c_del_button.set_sensitive (false);
315 LuaScriptManager::add_callback_btn_clicked ()
317 LuaInstance *li = LuaInstance::instance();
318 li->interactive_add (LuaScriptInfo::EditorHook, -1);
322 LuaScriptManager::del_callback_btn_clicked ()
324 TreeModel::Row row = *(_c_view.get_selection()->get_selected());
326 LuaInstance *li = LuaInstance::instance();
327 if (!li->unregister_lua_slot (row[_c_model.id])) {
333 LuaScriptManager::set_callback_script_name (PBD::ID id, const std::string& name, const ActionHook& ah)
336 typedef Gtk::TreeModel::Children type_children;
337 type_children children = _c_store->children();
338 for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter) {
339 Gtk::TreeModel::Row row = *iter;
340 PBD::ID i = row[_c_model.id];
342 _c_store->erase (iter);
347 TreeModel::Row r = *_c_store->append ();
349 r[_c_model.name] = name;
351 for (uint32_t i = 0; i < LuaSignal::LAST_SIGNAL; ++i) {
353 if (!sig.empty()) sig += ", ";
354 sig += enum2str (LuaSignal::LuaSignal (i));
357 r[_c_model.signals] = sig;
359 callback_selection_changed ();
364 LuaScriptManager::setup_session_scripts ()
370 std::vector<std::string> reg = _session->registered_lua_functions ();
371 for (std::vector<string>::const_iterator i = reg.begin(); i != reg.end(); ++i) {
372 TreeModel::Row r = *_s_store->append ();
373 r[_s_model.name] = *i;
375 session_script_selection_changed ();
379 LuaScriptManager::session_script_selection_changed ()
382 _s_del_button.set_sensitive (false);
383 _s_add_button.set_sensitive (false);
386 TreeModel::Row row = *(_s_view.get_selection()->get_selected());
388 _s_del_button.set_sensitive (true);
390 _s_del_button.set_sensitive (false);
392 _s_add_button.set_sensitive (true);
396 LuaScriptManager::add_sess_btn_clicked ()
401 LuaInstance *li = LuaInstance::instance();
402 li->interactive_add (LuaScriptInfo::Session, -1);
406 LuaScriptManager::del_sess_btn_clicked ()
409 TreeModel::Row row = *(_s_view.get_selection()->get_selected());
410 const std::string& name = row[_s_model.name];
412 _session->unregister_lua_function (name);
413 } catch (luabridge::LuaException const& e) {
414 string msg = string_compose (_("Session script '%1' removal failed: %2"), name, e.what ());
415 MessageDialog am (msg);