Plugin selector useability changes, fix mouse grab bug in plugin barcontroller, preve...
[ardour.git] / gtk2_ardour / plugin_selector.cc
1 /*
2     Copyright (C) 2000 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (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., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <cstdio>
21 #include <lrdf.h>
22
23 #include <gtkmm/table.h>
24 #include <gtkmm/stock.h>
25 #include <gtkmm/button.h>
26 #include <gtkmm/notebook.h>
27
28 #include <ardour/plugin_manager.h>
29 #include <ardour/plugin.h>
30 #include <ardour/configuration.h>
31
32 #include "ardour_ui.h"
33 #include "plugin_selector.h"
34 #include "gui_thread.h"
35
36 #include "i18n.h"
37
38 using namespace ARDOUR;
39 using namespace Gtk;
40
41 PluginSelector::PluginSelector (PluginManager *mgr)
42         : ArdourDialog (_("ardour: plugins"), true, false)
43 {
44         set_position (Gtk::WIN_POS_MOUSE);
45         set_name ("PluginSelectorWindow");
46         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
47
48         manager = mgr;
49         session = 0;
50         o_selected_plug = -1;
51         i_selected_plug = 0;
52
53         lmodel = Gtk::ListStore::create(lcols);
54         ladspa_display.set_model (lmodel);
55         ladspa_display.append_column (_("Available LADSPA Plugins"), lcols.name);
56         ladspa_display.append_column (_("Type"), lcols.type);
57         ladspa_display.append_column (_("# Inputs"),lcols.ins);
58         ladspa_display.append_column (_("# Outputs"), lcols.outs);
59         ladspa_display.set_headers_visible (true);
60         ladspa_display.set_reorderable (false);
61         lscroller.set_border_width(10);
62         lscroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
63         lscroller.add(ladspa_display);
64
65         amodel = Gtk::ListStore::create(acols);
66         added_list.set_model (amodel);
67         added_list.append_column (_("Plugins to be Connected to Insert"), acols.text);
68         added_list.set_headers_visible (true);
69         added_list.set_reorderable (false);
70
71         for (int i = 0; i <=3; i++) {
72                 Gtk::TreeView::Column* column = ladspa_display.get_column(i);
73                 column->set_sort_column(i);
74         }
75
76 #ifdef VST_SUPPORT
77         vmodel = ListStore::create(vcols);
78         vst_display.set_model (vmodel);
79         vst_display.append_column (_("Available plugins"), vcols.name);
80         vst_display.append_column (_("# Inputs"), vcols.ins);
81         vst_display.append_column (_("# Outputs"), vcols.outs);
82         vst_display.set_headers_visible (true);
83         vst_display.set_reorderable (false);
84         vscroller.set_border_width(10);
85         vscroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
86         vscroller.add(vst_display);
87
88         for (int i = 0; i <=2; i++) {
89                 Gtk::TreeView::Column* column = vst_display.get_column(i);
90                 column->set_sort_column(i);
91         }
92 #endif
93         ascroller.set_border_width(10);
94         ascroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
95         ascroller.add(added_list);
96         btn_add = manage(new Gtk::Button(Stock::ADD));
97         ARDOUR_UI::instance()->tooltips().set_tip(*btn_add, _("Add a plugin to the effect list"));
98         btn_add->set_sensitive (false);
99         btn_remove = manage(new Gtk::Button(Stock::REMOVE));
100         btn_remove->set_sensitive (false);
101         ARDOUR_UI::instance()->tooltips().set_tip(*btn_remove, _("Remove a plugin from the effect list"));
102         Gtk::Button *btn_update = manage(new Gtk::Button(Stock::REFRESH));
103         ARDOUR_UI::instance()->tooltips().set_tip(*btn_update, _("Update available plugins"));
104
105         btn_add->set_name("PluginSelectorButton");
106         btn_remove->set_name("PluginSelectorButton");
107
108         Gtk::Table* table = manage(new Gtk::Table(7, 10));
109         table->set_size_request(750, 500);
110         table->attach(notebook, 0, 7, 0, 5);
111
112         table->attach(*btn_add, 1, 2, 5, 6, Gtk::FILL, Gtk::FILL, 5, 5);
113         table->attach(*btn_remove, 3, 4, 5, 6, Gtk::FILL, Gtk::FILL, 5, 5);
114         table->attach(*btn_update, 5, 6, 5, 6, Gtk::FILL, Gtk::FILL, 5, 5);
115
116         table->attach(ascroller, 0, 7, 7, 9);
117
118         add_button (Stock::CANCEL, RESPONSE_CANCEL);
119         add_button (Stock::CONNECT, RESPONSE_APPLY);
120         set_default_response (RESPONSE_APPLY);
121         set_response_sensitive (RESPONSE_APPLY, false);
122         get_vbox()->pack_start (*table);
123
124         using namespace Gtk::Notebook_Helpers;
125         notebook.pages().push_back (TabElem (lscroller, _("LADSPA")));
126 #ifdef VST_SUPPORT
127         if (Config->get_use_vst()) {
128                 notebook.pages().push_back (TabElem (vscroller, _("VST")));
129         }
130 #endif
131
132         table->set_name("PluginSelectorTable");
133         ladspa_display.set_name("PluginSelectorDisplay");
134         //ladspa_display.set_name("PluginSelectorList");
135         added_list.set_name("PluginSelectorList");
136
137         ladspa_display.signal_button_press_event().connect_notify (mem_fun(*this, &PluginSelector::row_clicked));
138 #ifdef VST_SUPPORT
139         if (Config->get_use_vst()) {
140                 vst_display.signal_button_press_event().connect_notify (mem_fun(*this, &PluginSelector::row_clicked));
141                 vst_display.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::vst_display_selection_changed));
142         }
143 #endif
144         
145         btn_update->signal_clicked().connect (mem_fun(*this, &PluginSelector::btn_update_clicked));
146         btn_add->signal_clicked().connect(mem_fun(*this, &PluginSelector::btn_add_clicked));
147         btn_remove->signal_clicked().connect(mem_fun(*this, &PluginSelector::btn_remove_clicked));
148         ladspa_display.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::ladspa_display_selection_changed));
149         added_list.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::added_list_selection_changed));
150
151         input_refiller ();
152 }
153
154 void
155 PluginSelector::row_clicked(GdkEventButton* event)
156 {
157         if (event->type == GDK_2BUTTON_PRESS)
158                 btn_add_clicked();
159 }
160
161 void
162 PluginSelector::set_session (Session* s)
163 {
164         ENSURE_GUI_THREAD(bind (mem_fun(*this, &PluginSelector::set_session), s));
165         
166         session = s;
167
168         if (session) {
169                 session->going_away.connect (bind (mem_fun(*this, &PluginSelector::set_session), static_cast<Session*> (0)));
170         }
171 }
172
173 void
174 PluginSelector::_input_refiller (void *arg)
175 {
176         ((PluginSelector *) arg)->input_refiller ();
177 }
178
179 int compare(const void *left, const void *right)
180 {
181   return strcmp(*((char**)left), *((char**)right));
182 }
183
184 void
185 PluginSelector::input_refiller ()
186 {
187         guint row;
188         list<PluginInfo *> &plugs = manager->ladspa_plugin_info ();
189         list<PluginInfo *>::iterator i;
190         char ibuf[16], obuf[16];
191         lmodel->clear();
192 #ifdef VST_SUPPORT
193         vmodel->clear();
194 #endif
195         // Insert into GTK list
196         for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) {
197                 snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs);
198                 snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs);         
199                 
200                 Gtk::TreeModel::Row newrow = *(lmodel->append());
201                 newrow[lcols.name] = (*i)->name.c_str();
202                 newrow[lcols.type] = (*i)->category.c_str();
203                 newrow[lcols.ins] = ibuf;
204                 newrow[lcols.outs] = obuf;
205                 newrow[lcols.plugin] = *i;
206         }
207
208         lmodel->set_sort_column (0, Gtk::SORT_ASCENDING);
209 }
210
211 #ifdef VST_SUPPORT
212
213 void
214 PluginSelector::_vst_refiller (void *arg)
215 {
216         ((PluginSelector *) arg)->vst_refiller ();
217 }
218
219 void
220 PluginSelector::vst_refiller ()
221 {
222         guint row;
223         list<PluginInfo *> &plugs = manager->vst_plugin_info ();
224         list<PluginInfo *>::iterator i;
225         char ibuf[16], obuf[16];
226         
227         // Insert into GTK list
228         for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) {
229
230                 snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs);
231                 snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs);         
232                 
233                 Gtk::TreeModel::Row newrow = *(vmodel->append());
234                 newrow[vcols.name] = (*i)->name.c_str();
235                 newrow[vcols.ins] = ibuf;
236                 newrow[vcols.outs] = obuf;
237                 newrow[vcols.plugin] = *i;
238         }
239         vmodel->set_sort_column (0, Gtk::SORT_ASCENDING);
240 }
241 #endif
242
243 void
244 PluginSelector::use_plugin (PluginInfo* pi)
245 {
246         list<PluginInfo *>::iterator i;
247
248         if (pi == 0 || session == 0) {
249                 return;
250         }
251
252         Plugin *plugin = manager->load (*session, pi);
253
254         if (plugin) {
255                 PluginCreated (plugin);
256         }
257 }
258
259 void
260 PluginSelector::btn_add_clicked()
261 {
262         bool vst = notebook.get_current_page(); // 0 = LADSPA, 1 = VST
263         std::string name;
264         ARDOUR::PluginInfo *pi;
265         Gtk::TreeModel::Row newrow = *(amodel->append());
266         
267         if (vst) {
268 #ifdef VST_SUPPORT
269                 Gtk::TreeModel::Row row = *(vst_display.get_selection()->get_selected());
270                 name = row[vcols.name];
271                 pi = row[vcols.plugin];
272                 added_plugins.push_back (row[vcols.plugin]);
273 #endif
274         } else {
275                 Gtk::TreeModel::Row row = *(ladspa_display.get_selection()->get_selected());
276                 name = row[lcols.name];
277                 pi = row[lcols.plugin];
278                 added_plugins.push_back (row[lcols.plugin]);
279         }
280         newrow[acols.text] = name;
281         newrow[acols.plugin] = pi;
282
283         if (!amodel->children().empty()) {
284           set_response_sensitive (RESPONSE_APPLY, true);
285         }
286 }
287
288 void
289 PluginSelector::btn_remove_clicked()
290 {
291         list<PluginInfo*>::iterator i;
292         Gtk::TreeModel::iterator iter = added_list.get_selection()->get_selected();
293         for (i = added_plugins.begin(); (*i) != (*iter)[acols.plugin]; ++i);
294
295         added_plugins.erase(i); 
296         amodel->erase(iter);
297         if (amodel->children().empty()) {
298           set_response_sensitive (RESPONSE_APPLY, false);
299         }
300
301
302 }
303
304 void
305 PluginSelector::btn_update_clicked()
306 {
307         manager->refresh ();
308         input_refiller ();
309 }
310
311 #ifdef VST_SUPPORT
312 void
313 PluginSelector::vst_display_selection_changed()
314 {
315   if (vst_display.get_selection()->count_selected_rows() != 0) {
316     btn_add->set_sensitive (true);
317   } else {
318     btn_add->set_sensitive (false);
319   }
320 }
321 #endif
322
323 void
324 PluginSelector::ladspa_display_selection_changed()
325 {
326   if (ladspa_display.get_selection()->count_selected_rows() != 0) {
327     btn_add->set_sensitive (true);
328   } else {
329     btn_add->set_sensitive (false);
330   }
331 }
332
333 void
334 PluginSelector::added_list_selection_changed()
335 {
336   if (added_list.get_selection()->count_selected_rows() != 0) {
337     btn_remove->set_sensitive (true);
338   } else {
339     btn_remove->set_sensitive (false);
340   }
341 }
342
343 int
344 PluginSelector::run ()
345 {
346         ResponseType r;
347         list<PluginInfo*>::iterator i;
348
349         r = (ResponseType) Dialog::run ();
350
351         switch (r) {
352         case RESPONSE_APPLY:
353                 for (i = added_plugins.begin(); i != added_plugins.end(); ++i){
354                         use_plugin (*i);
355                 }
356                 break;
357
358         default:
359                 break;
360         }
361
362         cleanup ();
363
364         return (int) r;
365 }
366
367 void
368 PluginSelector::cleanup ()
369 {
370         hide();
371         added_plugins.clear();
372         amodel->clear();
373 }
374