fix copy/paste typo in in 5e0f0fc
[ardour.git] / gtk2_ardour / lua_script_manager.cc
1 /*
2  * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 #include "gtkmm2ext/utils.h"
20
21 #include "lua_script_manager.h"
22 #include "script_selector.h"
23 #include "i18n.h"
24
25 using namespace std;
26 using namespace Gtk;
27 using namespace ARDOUR;
28
29 LuaScriptManager::LuaScriptManager ()
30         : ArdourWindow (_("Script Manager"))
31         , _a_set_button (_("Add/Set"))
32         , _a_del_button (_("Remove"))
33         , _a_edit_button (_("Edit"))
34         , _a_call_button (_("Call"))
35         , _c_add_button (_("New Hook"))
36         , _c_del_button (_("Remove"))
37 {
38         /* action script page */
39         _a_store = ListStore::create (_a_model);
40         _a_view.set_model (_a_store);
41         _a_view.append_column (_("Action"), _a_model.action);
42         _a_view.append_column (_("Name"), _a_model.name);
43         _a_view.get_column(0)->set_resizable (true);
44         _a_view.get_column(0)->set_expand (true);
45         _a_view.get_column(1)->set_resizable (true);
46         _a_view.get_column(1)->set_expand (true);
47
48         Gtk::HBox* edit_box = manage (new Gtk::HBox);
49         edit_box->set_spacing(3);
50
51         edit_box->pack_start (_a_set_button, true, true);
52         edit_box->pack_start (_a_del_button, true, true);
53         edit_box->pack_start (_a_edit_button, true, true);
54         edit_box->pack_start (_a_call_button, true, true);
55
56         _a_set_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::set_action_btn_clicked));
57         _a_del_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::del_action_btn_clicked));
58         _a_edit_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::edit_action_btn_clicked));
59         _a_call_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::call_action_btn_clicked));
60         _a_view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &LuaScriptManager::action_selection_changed));
61
62         LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &LuaScriptManager::set_action_script_name));
63         LuaInstance::instance()->SlotChanged.connect (sigc::mem_fun (*this, &LuaScriptManager::set_callback_script_name));
64
65         Gtk::VBox *vbox = manage (new VBox());
66         vbox->pack_start (_a_view, false, false);
67         vbox->pack_end (*edit_box, false, false);
68         vbox->show_all ();
69
70         pages.pages ().push_back (Notebook_Helpers::TabElem (*vbox, "Action Scripts"));
71
72         /* action hooks page */
73
74         _c_store = ListStore::create (_c_model);
75         _c_view.set_model (_c_store);
76         _c_view.append_column (_("Name"), _c_model.name);
77         _c_view.append_column (_("Signal(s)"), _c_model.signals);
78         _c_view.get_column(0)->set_resizable (true);
79         _c_view.get_column(0)->set_expand (true);
80         _c_view.get_column(1)->set_resizable (true);
81         _c_view.get_column(1)->set_expand (true);
82         Gtk::CellRendererText* r = dynamic_cast<Gtk::CellRendererText*>(_c_view.get_column_cell_renderer (1));
83         r->property_ellipsize () = Pango::ELLIPSIZE_MIDDLE;
84
85         edit_box = manage (new Gtk::HBox);
86         edit_box->set_spacing(3);
87         edit_box->pack_start (_c_add_button, true, true);
88         edit_box->pack_start (_c_del_button, true, true);
89
90         _c_add_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::add_callback_btn_clicked));
91         _c_del_button.signal_clicked().connect (sigc::mem_fun(*this, &LuaScriptManager::del_callback_btn_clicked));
92         _c_view.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &LuaScriptManager::callback_selection_changed));
93
94         vbox = manage (new VBox());
95         vbox->pack_start (_c_view, false, false);
96         vbox->pack_end (*edit_box, false, false);
97         vbox->show_all ();
98
99         pages.pages ().push_back (Notebook_Helpers::TabElem (*vbox, "Action Hooks"));
100
101
102         add (pages);
103         pages.show();
104
105         setup_actions ();
106         setup_callbacks ();
107
108         action_selection_changed ();
109         callback_selection_changed ();
110 }
111
112 bool
113 LuaScriptManager::on_delete_event (GdkEventAny*)
114 {
115         return false;
116 }
117
118 void
119 LuaScriptManager::session_going_away ()
120 {
121         ArdourWindow::session_going_away ();
122         hide_all();
123 }
124
125 void
126 LuaScriptManager::setup_actions ()
127 {
128         LuaInstance *li = LuaInstance::instance();
129         for (int i = 0; i < 9; ++i) {
130                 std::string name;
131                 TreeModel::Row r = *_a_store->append ();
132                 r[_a_model.id] = i;
133                 r[_a_model.action] = string_compose (_("Action %1"), i + 1);
134                 if (li->lua_action_name (i, name)) {
135                         r[_a_model.name] = name;
136                         r[_a_model.enabled] = true;
137                 } else {
138                         r[_a_model.name] = _("Unset");
139                         r[_a_model.enabled] = false;
140                 }
141         }
142 }
143
144 void
145 LuaScriptManager::action_selection_changed ()
146 {
147         TreeModel::Row row = *(_a_view.get_selection()->get_selected());
148         if (row) {
149                 _a_set_button.set_sensitive (true);
150         }
151         else {
152                 _a_set_button.set_sensitive (false);
153         }
154
155         if (row && row[_a_model.enabled]) {
156                 _a_del_button.set_sensitive (true);
157                 _a_edit_button.set_sensitive (false); // TODO
158                 _a_call_button.set_sensitive (true);
159         } else {
160                 _a_del_button.set_sensitive (false);
161                 _a_edit_button.set_sensitive (false);
162                 _a_call_button.set_sensitive (false);
163         }
164 }
165
166 void
167 LuaScriptManager::set_action_btn_clicked ()
168 {
169         TreeModel::Row row = *(_a_view.get_selection()->get_selected());
170         assert (row);
171         LuaInstance *li = LuaInstance::instance();
172         li->interactive_add (LuaScriptInfo::EditorAction, row[_a_model.id]);
173 }
174
175 void
176 LuaScriptManager::del_action_btn_clicked ()
177 {
178         TreeModel::Row row = *(_a_view.get_selection()->get_selected());
179         assert (row);
180         LuaInstance *li = LuaInstance::instance();
181         if (!li->remove_lua_action (row[_a_model.id])) {
182                 // error
183         }
184 }
185
186 void
187 LuaScriptManager::call_action_btn_clicked ()
188 {
189         TreeModel::Row row = *(_a_view.get_selection()->get_selected());
190         assert (row && row[_a_model.enabled]);
191         LuaInstance *li = LuaInstance::instance();
192         li->call_action (row[_a_model.id]);
193 }
194
195 void
196 LuaScriptManager::edit_action_btn_clicked ()
197 {
198         TreeModel::Row row = *(_a_view.get_selection()->get_selected());
199         assert (row);
200         int id = row[_a_model.id];
201         LuaInstance *li = LuaInstance::instance();
202         std::string name, script;
203         LuaScriptParamList args;
204         if (!li->lua_action (id, name, script, args)) {
205                 return;
206         }
207
208         // TODO text-editor window, update script directly
209
210         if (!LuaScripting::try_compile (script, args)) {
211                 // compilation failed, keep editing
212                 return;
213         }
214
215         if (li->set_lua_action (id, name, script, args)) {
216                 // OK
217         } else {
218                 // load failed,  keep editing..
219         }
220         action_selection_changed ();
221 }
222
223 void
224 LuaScriptManager::set_action_script_name (int i, const std::string& name)
225 {
226         typedef Gtk::TreeModel::Children type_children;
227         type_children children = _a_store->children();
228         for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter) {
229                 Gtk::TreeModel::Row row = *iter;
230                 if (row[_a_model.id] == i) {
231                         if (name.empty()) {
232                                 row[_a_model.enabled] = false;
233                                 row[_a_model.name] = _("Unset");
234                         } else {
235                                 row[_a_model.enabled] = true;
236                                 row[_a_model.name] = name;
237                         }
238                         break;
239                 }
240         }
241         action_selection_changed ();
242 }
243
244
245 void
246 LuaScriptManager::setup_callbacks ()
247 {
248         LuaInstance *li = LuaInstance::instance();
249         std::vector<PBD::ID> ids = li->lua_slots();
250         for (std::vector<PBD::ID>::const_iterator i = ids.begin(); i != ids.end(); ++i) {
251                 std::string name;
252                 std::string script;
253                 ActionHook ah;
254                 LuaScriptParamList lsp;
255                 if (li->lua_slot (*i, name, script, ah, lsp)) {
256                         set_callback_script_name (*i, name, ah);
257                 }
258         }
259 }
260
261 void
262 LuaScriptManager::callback_selection_changed ()
263 {
264         TreeModel::Row row = *(_c_view.get_selection()->get_selected());
265         if (row) {
266                 _c_del_button.set_sensitive (true);
267         } else {
268                 _c_del_button.set_sensitive (false);
269         }
270 }
271
272 void
273 LuaScriptManager::add_callback_btn_clicked ()
274 {
275         LuaInstance *li = LuaInstance::instance();
276         li->interactive_add (LuaScriptInfo::EditorHook, -1);
277 }
278
279 void
280 LuaScriptManager::del_callback_btn_clicked ()
281 {
282         TreeModel::Row row = *(_c_view.get_selection()->get_selected());
283         assert (row);
284         LuaInstance *li = LuaInstance::instance();
285         if (!li->unregister_lua_slot (row[_c_model.id])) {
286                 // error
287         }
288 }
289
290 void
291 LuaScriptManager::set_callback_script_name (PBD::ID id, const std::string& name, const ActionHook& ah)
292 {
293         if (name.empty()) {
294                 typedef Gtk::TreeModel::Children type_children;
295                 type_children children = _c_store->children();
296                 for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter) {
297                         Gtk::TreeModel::Row row = *iter;
298                         PBD::ID i = row[_c_model.id];
299                         if (i == id) {
300                                 _c_store->erase (iter);
301                                 break;
302                         }
303                 }
304         } else {
305                 TreeModel::Row r = *_c_store->append ();
306                 r[_c_model.id] = id;
307                 r[_c_model.name] = name;
308                 string sig;
309                 for (uint32_t i = 0; i < LuaSignal::LAST_SIGNAL; ++i) {
310                         if (ah[i]) {
311                                 if (!sig.empty()) sig += ", ";
312                                 sig += enum2str (LuaSignal::LuaSignal (i));
313                         }
314                 }
315                 r[_c_model.signals] = sig;
316         }
317         callback_selection_changed ();
318 }