enough with umpteen "i18n.h" files. Consolidate on pbd/i18n.h
[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 "pbd/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 void
113 LuaScriptManager::session_going_away ()
114 {
115         ArdourWindow::session_going_away ();
116         hide_all();
117 }
118
119 void
120 LuaScriptManager::setup_actions ()
121 {
122         LuaInstance *li = LuaInstance::instance();
123         for (int i = 0; i < 9; ++i) {
124                 std::string name;
125                 TreeModel::Row r = *_a_store->append ();
126                 r[_a_model.id] = i;
127                 r[_a_model.action] = string_compose (_("Action %1"), i + 1);
128                 if (li->lua_action_name (i, name)) {
129                         r[_a_model.name] = name;
130                         r[_a_model.enabled] = true;
131                 } else {
132                         r[_a_model.name] = _("Unset");
133                         r[_a_model.enabled] = false;
134                 }
135         }
136 }
137
138 void
139 LuaScriptManager::action_selection_changed ()
140 {
141         TreeModel::Row row = *(_a_view.get_selection()->get_selected());
142         if (row) {
143                 _a_set_button.set_sensitive (true);
144         }
145         else {
146                 _a_set_button.set_sensitive (false);
147         }
148
149         if (row && row[_a_model.enabled]) {
150                 _a_del_button.set_sensitive (true);
151                 _a_edit_button.set_sensitive (false); // TODO
152                 _a_call_button.set_sensitive (true);
153         } else {
154                 _a_del_button.set_sensitive (false);
155                 _a_edit_button.set_sensitive (false);
156                 _a_call_button.set_sensitive (false);
157         }
158 }
159
160 void
161 LuaScriptManager::set_action_btn_clicked ()
162 {
163         TreeModel::Row row = *(_a_view.get_selection()->get_selected());
164         assert (row);
165         LuaInstance *li = LuaInstance::instance();
166         li->interactive_add (LuaScriptInfo::EditorAction, row[_a_model.id]);
167 }
168
169 void
170 LuaScriptManager::del_action_btn_clicked ()
171 {
172         TreeModel::Row row = *(_a_view.get_selection()->get_selected());
173         assert (row);
174         LuaInstance *li = LuaInstance::instance();
175         if (!li->remove_lua_action (row[_a_model.id])) {
176                 // error
177         }
178 }
179
180 void
181 LuaScriptManager::call_action_btn_clicked ()
182 {
183         TreeModel::Row row = *(_a_view.get_selection()->get_selected());
184         assert (row && row[_a_model.enabled]);
185         LuaInstance *li = LuaInstance::instance();
186         li->call_action (row[_a_model.id]);
187 }
188
189 void
190 LuaScriptManager::edit_action_btn_clicked ()
191 {
192         TreeModel::Row row = *(_a_view.get_selection()->get_selected());
193         assert (row);
194         int id = row[_a_model.id];
195         LuaInstance *li = LuaInstance::instance();
196         std::string name, script;
197         LuaScriptParamList args;
198         if (!li->lua_action (id, name, script, args)) {
199                 return;
200         }
201
202         // TODO text-editor window, update script directly
203
204         if (!LuaScripting::try_compile (script, args)) {
205                 // compilation failed, keep editing
206                 return;
207         }
208
209         if (li->set_lua_action (id, name, script, args)) {
210                 // OK
211         } else {
212                 // load failed,  keep editing..
213         }
214         action_selection_changed ();
215 }
216
217 void
218 LuaScriptManager::set_action_script_name (int i, const std::string& name)
219 {
220         typedef Gtk::TreeModel::Children type_children;
221         type_children children = _a_store->children();
222         for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter) {
223                 Gtk::TreeModel::Row row = *iter;
224                 if (row[_a_model.id] == i) {
225                         if (name.empty()) {
226                                 row[_a_model.enabled] = false;
227                                 row[_a_model.name] = _("Unset");
228                         } else {
229                                 row[_a_model.enabled] = true;
230                                 row[_a_model.name] = name;
231                         }
232                         break;
233                 }
234         }
235         action_selection_changed ();
236 }
237
238
239 void
240 LuaScriptManager::setup_callbacks ()
241 {
242         LuaInstance *li = LuaInstance::instance();
243         std::vector<PBD::ID> ids = li->lua_slots();
244         for (std::vector<PBD::ID>::const_iterator i = ids.begin(); i != ids.end(); ++i) {
245                 std::string name;
246                 std::string script;
247                 ActionHook ah;
248                 LuaScriptParamList lsp;
249                 if (li->lua_slot (*i, name, script, ah, lsp)) {
250                         set_callback_script_name (*i, name, ah);
251                 }
252         }
253 }
254
255 void
256 LuaScriptManager::callback_selection_changed ()
257 {
258         TreeModel::Row row = *(_c_view.get_selection()->get_selected());
259         if (row) {
260                 _c_del_button.set_sensitive (true);
261         } else {
262                 _c_del_button.set_sensitive (false);
263         }
264 }
265
266 void
267 LuaScriptManager::add_callback_btn_clicked ()
268 {
269         LuaInstance *li = LuaInstance::instance();
270         li->interactive_add (LuaScriptInfo::EditorHook, -1);
271 }
272
273 void
274 LuaScriptManager::del_callback_btn_clicked ()
275 {
276         TreeModel::Row row = *(_c_view.get_selection()->get_selected());
277         assert (row);
278         LuaInstance *li = LuaInstance::instance();
279         if (!li->unregister_lua_slot (row[_c_model.id])) {
280                 // error
281         }
282 }
283
284 void
285 LuaScriptManager::set_callback_script_name (PBD::ID id, const std::string& name, const ActionHook& ah)
286 {
287         if (name.empty()) {
288                 typedef Gtk::TreeModel::Children type_children;
289                 type_children children = _c_store->children();
290                 for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter) {
291                         Gtk::TreeModel::Row row = *iter;
292                         PBD::ID i = row[_c_model.id];
293                         if (i == id) {
294                                 _c_store->erase (iter);
295                                 break;
296                         }
297                 }
298         } else {
299                 TreeModel::Row r = *_c_store->append ();
300                 r[_c_model.id] = id;
301                 r[_c_model.name] = name;
302                 string sig;
303                 for (uint32_t i = 0; i < LuaSignal::LAST_SIGNAL; ++i) {
304                         if (ah[i]) {
305                                 if (!sig.empty()) sig += ", ";
306                                 sig += enum2str (LuaSignal::LuaSignal (i));
307                         }
308                 }
309                 r[_c_model.signals] = sig;
310         }
311         callback_selection_changed ();
312 }