Make global static children variable an xml node object variable.
[ardour.git] / gtk2_ardour / plugin_ui.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 <climits>
21 #include <cerrno>
22 #include <cmath>
23 #include <string>
24
25 #include <pbd/stl_delete.h>
26 #include <pbd/xml++.h>
27 #include <pbd/failed_constructor.h>
28
29 #include <gtkmm/widget.h>
30 #include <gtkmm2ext/click_box.h>
31 #include <gtkmm2ext/fastmeter.h>
32 #include <gtkmm2ext/barcontroller.h>
33 #include <gtkmm2ext/utils.h>
34 #include <gtkmm2ext/doi.h>
35 #include <gtkmm2ext/slider_controller.h>
36
37 #include <midi++/manager.h>
38
39 #include <ardour/plugin.h>
40 #include <ardour/insert.h>
41 #include <ardour/ladspa_plugin.h>
42 #ifdef VST_SUPPORT
43 #include <ardour/vst_plugin.h>
44 #endif
45 #ifdef HAVE_LV2
46 #include <ardour/lv2_plugin.h>
47 #include "lv2_plugin_ui.h"
48 #endif
49
50 #include <lrdf.h>
51
52 #include "ardour_ui.h"
53 #include "prompter.h"
54 #include "plugin_ui.h"
55 #include "utils.h"
56 #include "gui_thread.h"
57 #include "public_editor.h"
58 #include "keyboard.h"
59
60 #include "i18n.h"
61
62 using namespace std;
63 using namespace ARDOUR;
64 using namespace PBD;
65 using namespace Gtkmm2ext;
66 using namespace Gtk;
67 using namespace sigc;
68
69 PluginUIWindow::PluginUIWindow (Gtk::Window* win, boost::shared_ptr<PluginInsert> insert, bool scrollable)
70         : parent (win)
71 {
72         bool have_gui = false;
73         non_gtk_gui = false;
74         was_visible = false;
75
76         if (insert->plugin()->has_editor()) {
77                 switch (insert->type()) {
78                 case ARDOUR::VST:
79                         have_gui = create_vst_editor (insert);
80                         break;
81
82                 case ARDOUR::AudioUnit:
83                         have_gui = create_audiounit_editor (insert);
84                         break;
85                         
86                 case ARDOUR::LADSPA:
87                         error << _("Eh? LADSPA plugins don't have editors!") << endmsg;
88                         break;
89
90                 case ARDOUR::LV2:
91                         have_gui = create_lv2_editor (insert);
92                         break;
93
94                 default:
95 #ifndef VST_SUPPORT
96                         error << _("unknown type of editor-supplying plugin (note: no VST support in this version of ardour)")
97                               << endmsg;
98 #else
99                         error << _("unknown type of editor-supplying plugin")
100                               << endmsg;
101 #endif
102                         throw failed_constructor ();
103                 }
104
105         } 
106
107         if (!have_gui) {
108
109                 GenericPluginUI*  pu  = new GenericPluginUI (insert, scrollable);
110                 
111                 _pluginui = pu;
112                 add (*pu);
113                 
114                 set_wmclass (X_("ardour_plugin_editor"), "Ardour");
115
116                 signal_map_event().connect (mem_fun (*pu, &GenericPluginUI::start_updating));
117                 signal_unmap_event().connect (mem_fun (*pu, &GenericPluginUI::stop_updating));
118         }
119
120         // set_position (Gtk::WIN_POS_MOUSE);
121         set_name ("PluginEditor");
122         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
123
124         signal_delete_event().connect (bind (sigc::ptr_fun (just_hide_it), reinterpret_cast<Window*> (this)), false);
125         insert->GoingAway.connect (mem_fun(*this, &PluginUIWindow::plugin_going_away));
126
127         gint h = _pluginui->get_preferred_height ();
128         gint w = _pluginui->get_preferred_width ();
129
130         if (scrollable) {
131                 if (h > 600) h = 600;
132                 if (w > 600) w = 600;
133
134                 if (w < 0) {
135                         w = 450;
136                 }
137         }
138
139         set_default_size (w, h); 
140 }
141
142 PluginUIWindow::~PluginUIWindow ()
143 {
144 }
145
146 void
147 PluginUIWindow::set_parent (Gtk::Window* win)
148 {
149         parent = win;
150 }
151
152 void
153 PluginUIWindow::on_map ()
154 {
155         Window::on_map ();
156         set_keep_above (true);
157 }
158
159 bool
160 PluginUIWindow::on_enter_notify_event (GdkEventCrossing *ev)
161 {
162         Keyboard::the_keyboard().enter_window (ev, this);
163         return false;
164 }
165
166 bool
167 PluginUIWindow::on_leave_notify_event (GdkEventCrossing *ev)
168 {
169         Keyboard::the_keyboard().leave_window (ev, this);
170         return false;
171 }
172
173 void
174 PluginUIWindow::on_show ()
175 {
176         if (_pluginui) {
177                 _pluginui->update_presets ();
178         }
179
180         Window::on_show ();
181
182         if (parent) {
183                 // set_transient_for (*parent);
184         }
185 }
186
187 void
188 PluginUIWindow::on_hide ()
189 {
190         Window::on_hide ();
191 }
192
193 bool
194 PluginUIWindow::create_vst_editor(boost::shared_ptr<PluginInsert> insert)
195 {
196 #ifndef VST_SUPPORT
197         return false;
198 #else
199
200         boost::shared_ptr<VSTPlugin> vp;
201
202         if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (insert->plugin())) == 0) {
203                 error << _("unknown type of editor-supplying plugin (note: no VST support in this version of ardour)")
204                               << endmsg;
205                 throw failed_constructor ();
206         } else {
207                 VSTPluginUI* vpu = new VSTPluginUI (insert, vp);
208         
209                 _pluginui = vpu;
210                 add (*vpu);
211                 vpu->package (*this);
212         }
213
214         non_gtk_gui = true;
215         return true;
216 #endif
217 }
218
219 bool
220 PluginUIWindow::create_audiounit_editor (boost::shared_ptr<PluginInsert> insert)
221 {
222 #if !defined(HAVE_AUDIOUNITS) || !defined(GTKOSX)
223         return false;
224 #else
225         VBox* box;
226         _pluginui = create_au_gui (insert, &box);
227         add (*box);
228         non_gtk_gui = true;
229
230         extern sigc::signal<void,bool> ApplicationActivationChanged;
231         ApplicationActivationChanged.connect (mem_fun (*this, &PluginUIWindow::app_activated));
232
233         return true;
234 #endif
235 }
236
237 void
238 PluginUIWindow::app_activated (bool yn)
239 {
240 #if defined (HAVE_AUDIOUNITS) && defined(GTKOSX)
241         cerr << "APP activated ? " << yn << endl;
242         if (_pluginui) {
243                 if (yn) {
244                         if (was_visible) {
245                                 _pluginui->activate ();
246                                 present ();
247                                 was_visible = true;
248                         }
249                 } else {
250                         was_visible = is_visible();
251                         hide ();
252                         _pluginui->deactivate ();
253                 }
254         } 
255 #endif
256 }
257
258 bool
259 PluginUIWindow::create_lv2_editor(boost::shared_ptr<PluginInsert> insert)
260 {
261 #ifndef HAVE_LV2
262         return false;
263 #else
264
265         boost::shared_ptr<LV2Plugin> vp;
266         
267         if ((vp = boost::dynamic_pointer_cast<LV2Plugin> (insert->plugin())) == 0) {
268                 error << _("create_lv2_editor called on non-LV2 plugin") << endmsg;
269                 throw failed_constructor ();
270         } else {
271                 LV2PluginUI* lpu = new LV2PluginUI (insert, vp);
272                 _pluginui = lpu;
273                 add (*lpu);
274                 lpu->package (*this);
275         }
276
277         non_gtk_gui = false;
278         return true;
279 #endif
280 }
281
282 bool
283 PluginUIWindow::on_key_press_event (GdkEventKey* event)
284 {
285         if (non_gtk_gui) {
286                 return false;
287         }
288
289         if (!key_press_focus_accelerator_handler (*this, event)) {
290                 return PublicEditor::instance().on_key_press_event(event);
291         } else {
292                 return true;
293         }
294 }
295
296 bool
297 PluginUIWindow::on_key_release_event (GdkEventKey* event)
298 {
299         return true;
300 }
301
302 void
303 PluginUIWindow::plugin_going_away ()
304 {
305         ENSURE_GUI_THREAD(mem_fun(*this, &PluginUIWindow::plugin_going_away));
306         
307         if (_pluginui) {
308                 _pluginui->stop_updating(0);
309         }
310         delete_when_idle (this);
311 }
312
313 PlugUIBase::PlugUIBase (boost::shared_ptr<PluginInsert> pi)
314         : insert (pi),
315           plugin (insert->plugin()),
316           save_button(_("Add")),
317           bypass_button (_("Bypass"))
318 {
319         //preset_combo.set_use_arrows_always(true);
320         set_popdown_strings (preset_combo, plugin->get_presets());
321         preset_combo.set_size_request (100, -1);
322         preset_combo.set_active_text ("");
323         preset_combo.signal_changed().connect(mem_fun(*this, &PlugUIBase::setting_selected));
324
325         save_button.set_name ("PluginSaveButton");
326         save_button.signal_clicked().connect(mem_fun(*this, &PlugUIBase::save_plugin_setting));
327
328         insert->active_changed.connect (mem_fun(*this, &PlugUIBase::redirect_active_changed));
329         bypass_button.set_active (!pi->active());
330
331         bypass_button.set_name ("PluginBypassButton");
332         bypass_button.signal_toggled().connect (mem_fun(*this, &PlugUIBase::bypass_toggled));
333 }
334
335 void
336 PlugUIBase::redirect_active_changed (Redirect* r, void* src)
337 {
338         ENSURE_GUI_THREAD(bind (mem_fun(*this, &PlugUIBase::redirect_active_changed), r, src));
339         bypass_button.set_active (!r->active());
340 }
341
342 void
343 PlugUIBase::setting_selected()
344 {
345         if (preset_combo.get_active_text().length() > 0) {
346                 if (!plugin->load_preset(preset_combo.get_active_text())) {
347                         warning << string_compose(_("Plugin preset %1 not found"), preset_combo.get_active_text()) << endmsg;
348                 }
349         }
350 }
351
352 void
353 PlugUIBase::save_plugin_setting ()
354 {
355         ArdourPrompter prompter (true);
356         prompter.set_prompt(_("Name of New Preset:"));
357         prompter.add_button (Gtk::Stock::ADD, Gtk::RESPONSE_ACCEPT);
358         prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
359
360         prompter.show_all();
361
362         switch (prompter.run ()) {
363         case Gtk::RESPONSE_ACCEPT:
364
365                 string name;
366
367                 prompter.get_result(name);
368
369                 if (name.length()) {
370                         if(plugin->save_preset(name)){
371                                 set_popdown_strings (preset_combo, plugin->get_presets());
372                                 preset_combo.set_active_text (name);
373                         }
374                 }
375                 break;
376         }
377 }
378
379 void
380 PlugUIBase::bypass_toggled ()
381 {
382         bool x;
383
384         if ((x = bypass_button.get_active()) == insert->active()) {
385                 insert->set_active (!x, this);
386                 if (insert->active()) {
387                         bypass_button.set_label (_("Bypass"));
388                 } else {
389                         bypass_button.set_label (_("Active"));
390                 }
391         }
392 }
393
394 void
395 PlugUIBase::update_presets ()
396 {
397         set_popdown_strings (preset_combo, plugin->get_presets());
398 }