Remove cruft
[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 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 #include <climits>
25 #include <cerrno>
26 #include <cmath>
27 #include <string>
28
29 #include "pbd/stl_delete.h"
30 #include "pbd/xml++.h"
31 #include "pbd/failed_constructor.h"
32
33 #include "gtkmm/widget.h"
34 #include "gtkmm/box.h"
35
36 #include "gtkmm2ext/utils.h"
37 #include "gtkmm2ext/doi.h"
38 #include "gtkmm2ext/application.h"
39
40 #include "widgets/tooltips.h"
41 #include "widgets/fastmeter.h"
42
43 #include "ardour/session.h"
44 #include "ardour/plugin.h"
45 #include "ardour/plugin_insert.h"
46 #include "ardour/ladspa_plugin.h"
47 #ifdef WINDOWS_VST_SUPPORT
48 #include "ardour/windows_vst_plugin.h"
49 #include "windows_vst_plugin_ui.h"
50 #endif
51 #ifdef LXVST_SUPPORT
52 #include "ardour/lxvst_plugin.h"
53 #include "lxvst_plugin_ui.h"
54 #endif
55 #ifdef MACVST_SUPPORT
56 #include "ardour/mac_vst_plugin.h"
57 #include "vst_plugin_ui.h"
58 #endif
59 #ifdef LV2_SUPPORT
60 #include "ardour/lv2_plugin.h"
61 #include "lv2_plugin_ui.h"
62 #endif
63
64 #include "ardour_window.h"
65 #include "ardour_ui.h"
66 #include "plugin_ui.h"
67 #include "utils.h"
68 #include "gui_thread.h"
69 #include "public_editor.h"
70 #include "processor_box.h"
71 #include "keyboard.h"
72 #include "latency_gui.h"
73 #include "plugin_eq_gui.h"
74 #include "new_plugin_preset_dialog.h"
75
76 #include "pbd/i18n.h"
77
78 using namespace std;
79 using namespace ARDOUR;
80 using namespace ARDOUR_UI_UTILS;
81 using namespace ArdourWidgets;
82 using namespace PBD;
83 using namespace Gtkmm2ext;
84 using namespace Gtk;
85
86 PluginUIWindow::PluginUIWindow (
87         boost::shared_ptr<PluginInsert> insert,
88         bool                            scrollable,
89         bool                            editor)
90         : ArdourWindow (string())
91         , was_visible (false)
92         , _keyboard_focused (false)
93 #ifdef AUDIOUNIT_SUPPORT
94         , pre_deactivate_x (-1)
95         , pre_deactivate_y (-1)
96 #endif
97
98 {
99         bool have_gui = false;
100         Label* label = manage (new Label());
101         label->set_markup ("<b>THIS IS THE PLUGIN UI</b>");
102
103         if (editor && insert->plugin()->has_editor()) {
104                 switch (insert->type()) {
105                 case ARDOUR::Windows_VST:
106                         have_gui = create_windows_vst_editor (insert);
107                         break;
108
109                 case ARDOUR::LXVST:
110                         have_gui = create_lxvst_editor (insert);
111                         break;
112
113                 case ARDOUR::MacVST:
114                         have_gui = create_mac_vst_editor (insert);
115                         break;
116
117                 case ARDOUR::AudioUnit:
118                         have_gui = create_audiounit_editor (insert);
119                         break;
120
121                 case ARDOUR::LADSPA:
122                         error << _("Eh? LADSPA plugins don't have editors!") << endmsg;
123                         break;
124
125                 case ARDOUR::LV2:
126                         have_gui = create_lv2_editor (insert);
127                         break;
128
129                 default:
130 #ifndef WINDOWS_VST_SUPPORT
131                         error << string_compose (_("unknown type of editor-supplying plugin (note: no VST support in this version of %1)"), PROGRAM_NAME)
132                               << endmsg;
133 #else
134                         error << _("unknown type of editor-supplying plugin")
135                               << endmsg;
136 #endif
137                         throw failed_constructor ();
138                 }
139
140         }
141
142         if (!have_gui) {
143                 GenericPluginUI* pu = new GenericPluginUI (insert, scrollable);
144
145                 _pluginui = pu;
146                 _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
147                 add (*pu);
148                 set_wmclass (X_("ardour_plugin_editor"), PROGRAM_NAME);
149
150                 signal_map_event().connect (sigc::mem_fun (*pu, &GenericPluginUI::start_updating));
151                 signal_unmap_event().connect (sigc::mem_fun (*pu, &GenericPluginUI::stop_updating));
152         }
153
154         set_name ("PluginEditor");
155         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
156
157         insert->DropReferences.connect (death_connection, invalidator (*this), boost::bind (&PluginUIWindow::plugin_going_away, this), gui_context());
158
159         gint h = _pluginui->get_preferred_height ();
160         gint w = _pluginui->get_preferred_width ();
161
162         if (scrollable) {
163                 if (h > 600) h = 600;
164         }
165
166         set_default_size (w, h);
167         set_resizable (_pluginui->resizable());
168 }
169
170 PluginUIWindow::~PluginUIWindow ()
171 {
172 #ifndef NDEBUG
173         cerr << "PluginWindow deleted for " << this << endl;
174 #endif
175         delete _pluginui;
176 }
177
178 void
179 PluginUIWindow::on_show ()
180 {
181         set_role("plugin_ui");
182
183         if (_pluginui) {
184                 _pluginui->update_preset_list ();
185                 _pluginui->update_preset ();
186         }
187
188         if (_pluginui) {
189 #if defined (HAVE_AUDIOUNITS) && defined(__APPLE__)
190                 if (pre_deactivate_x >= 0) {
191                         move (pre_deactivate_x, pre_deactivate_y);
192                 }
193 #endif
194
195                 if (_pluginui->on_window_show (_title)) {
196                         Window::on_show ();
197                 }
198         }
199 }
200
201 void
202 PluginUIWindow::on_hide ()
203 {
204 #if defined (HAVE_AUDIOUNITS) && defined(__APPLE__)
205         get_position (pre_deactivate_x, pre_deactivate_y);
206 #endif
207
208         Window::on_hide ();
209
210         if (_pluginui) {
211                 _pluginui->on_window_hide ();
212         }
213 }
214
215 void
216 PluginUIWindow::set_title(const std::string& title)
217 {
218         Gtk::Window::set_title(title);
219         _title = title;
220 }
221
222 bool
223 #ifdef WINDOWS_VST_SUPPORT
224 PluginUIWindow::create_windows_vst_editor(boost::shared_ptr<PluginInsert> insert)
225 #else
226 PluginUIWindow::create_windows_vst_editor(boost::shared_ptr<PluginInsert>)
227 #endif
228 {
229 #ifndef WINDOWS_VST_SUPPORT
230         return false;
231 #else
232
233         boost::shared_ptr<WindowsVSTPlugin> vp;
234
235         if ((vp = boost::dynamic_pointer_cast<WindowsVSTPlugin> (insert->plugin())) == 0) {
236                 error << string_compose (_("unknown type of editor-supplying plugin (note: no VST support in this version of %1)"), PROGRAM_NAME)
237                       << endmsg;
238                 throw failed_constructor ();
239         } else {
240                 WindowsVSTPluginUI* vpu = new WindowsVSTPluginUI (insert, vp, GTK_WIDGET(this->gobj()));
241
242                 _pluginui = vpu;
243                 _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
244                 add (*vpu);
245                 vpu->package (*this);
246         }
247
248         return true;
249 #endif
250 }
251
252 bool
253 #ifdef LXVST_SUPPORT
254 PluginUIWindow::create_lxvst_editor(boost::shared_ptr<PluginInsert> insert)
255 #else
256 PluginUIWindow::create_lxvst_editor(boost::shared_ptr<PluginInsert>)
257 #endif
258 {
259 #ifndef LXVST_SUPPORT
260         return false;
261 #else
262
263         boost::shared_ptr<LXVSTPlugin> lxvp;
264
265         if ((lxvp = boost::dynamic_pointer_cast<LXVSTPlugin> (insert->plugin())) == 0) {
266                 error << string_compose (_("unknown type of editor-supplying plugin (note: no linuxVST support in this version of %1)"), PROGRAM_NAME)
267                       << endmsg;
268                 throw failed_constructor ();
269         } else {
270                 LXVSTPluginUI* lxvpu = new LXVSTPluginUI (insert, lxvp);
271
272                 _pluginui = lxvpu;
273                 _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
274                 add (*lxvpu);
275                 lxvpu->package (*this);
276         }
277
278         return true;
279 #endif
280 }
281
282 bool
283 #ifdef MACVST_SUPPORT
284 PluginUIWindow::create_mac_vst_editor (boost::shared_ptr<PluginInsert> insert)
285 #else
286 PluginUIWindow::create_mac_vst_editor (boost::shared_ptr<PluginInsert>)
287 #endif
288 {
289 #ifndef MACVST_SUPPORT
290         return false;
291 #else
292         boost::shared_ptr<MacVSTPlugin> mvst;
293         if ((mvst = boost::dynamic_pointer_cast<MacVSTPlugin> (insert->plugin())) == 0) {
294                 error << string_compose (_("unknown type of editor-supplying plugin (note: no MacVST support in this version of %1)"), PROGRAM_NAME)
295                       << endmsg;
296                 throw failed_constructor ();
297         }
298         VSTPluginUI* vpu = create_mac_vst_gui (insert);
299         _pluginui = vpu;
300         _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
301         add (*vpu);
302         vpu->package (*this);
303
304         Application::instance()->ActivationChanged.connect (mem_fun (*this, &PluginUIWindow::app_activated));
305
306         return true;
307 #endif
308 }
309
310
311 bool
312 #ifdef AUDIOUNIT_SUPPORT
313 PluginUIWindow::create_audiounit_editor (boost::shared_ptr<PluginInsert> insert)
314 #else
315 PluginUIWindow::create_audiounit_editor (boost::shared_ptr<PluginInsert>)
316 #endif
317 {
318 #ifndef AUDIOUNIT_SUPPORT
319         return false;
320 #else
321         VBox* box;
322         _pluginui = create_au_gui (insert, &box);
323         _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
324         add (*box);
325
326         Application::instance()->ActivationChanged.connect (mem_fun (*this, &PluginUIWindow::app_activated));
327
328         return true;
329 #endif
330 }
331
332 void
333 #ifdef __APPLE__
334 PluginUIWindow::app_activated (bool yn)
335 #else
336 PluginUIWindow::app_activated (bool)
337 #endif
338 {
339 #ifdef AUDIOUNIT_SUPPORT
340         if (_pluginui) {
341                 if (yn) {
342                         if (was_visible) {
343                                 _pluginui->activate ();
344                                 if (pre_deactivate_x >= 0) {
345                                         move (pre_deactivate_x, pre_deactivate_y);
346                                 }
347                                 present ();
348                                 was_visible = true;
349                         }
350                 } else {
351                         was_visible = is_visible();
352                         get_position (pre_deactivate_x, pre_deactivate_y);
353                         hide ();
354                         _pluginui->deactivate ();
355                 }
356         }
357 #endif
358 }
359
360 bool
361 PluginUIWindow::create_lv2_editor(boost::shared_ptr<PluginInsert> insert)
362 {
363 #ifdef HAVE_SUIL
364         boost::shared_ptr<LV2Plugin> vp;
365
366         if ((vp = boost::dynamic_pointer_cast<LV2Plugin> (insert->plugin())) == 0) {
367                 error << _("create_lv2_editor called on non-LV2 plugin") << endmsg;
368                 throw failed_constructor ();
369         } else {
370                 LV2PluginUI* lpu = new LV2PluginUI (insert, vp);
371                 _pluginui = lpu;
372                 add (*lpu);
373                 lpu->package (*this);
374                 _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
375         }
376
377         return true;
378 #else
379         return false;
380 #endif
381 }
382
383 void
384 PluginUIWindow::keyboard_focused (bool yn)
385 {
386         _keyboard_focused = yn;
387 }
388
389 bool
390 PluginUIWindow::on_key_press_event (GdkEventKey* event)
391 {
392         if (_keyboard_focused) {
393                 if (_pluginui) {
394                         _pluginui->grab_focus();
395                         if (_pluginui->non_gtk_gui()) {
396                                 _pluginui->forward_key_event (event);
397                         } else {
398                                         return relay_key_press (event, this);
399                         }
400                 }
401                 return true;
402         }
403         /* for us to be getting key press events, there really
404            MUST be a _pluginui, but just to be safe, check ...
405         */
406
407         if (_pluginui) {
408                 _pluginui->grab_focus();
409                 if (_pluginui->non_gtk_gui()) {
410                         /* pass main window as the window for the event
411                            to be handled in, not this one, because there are
412                            no widgets in this window that we want to have
413                            key focus.
414                         */
415                         return relay_key_press (event, &ARDOUR_UI::instance()->main_window());
416                 } else {
417                         return relay_key_press (event, this);
418                 }
419         }
420
421         return false;
422 }
423
424 bool
425 PluginUIWindow::on_key_release_event (GdkEventKey *event)
426 {
427         if (_keyboard_focused) {
428                 if (_pluginui) {
429                         if (_pluginui->non_gtk_gui()) {
430                                 _pluginui->forward_key_event (event);
431                         }
432                 }
433         } else {
434                 gtk_window_propagate_key_event (GTK_WINDOW(gobj()), event);
435         }
436         /* don't forward releases */
437         return true;
438 }
439
440 void
441 PluginUIWindow::plugin_going_away ()
442 {
443         ENSURE_GUI_THREAD (*this, &PluginUIWindow::plugin_going_away)
444
445         if (_pluginui) {
446                 _pluginui->stop_updating(0);
447         }
448
449         death_connection.disconnect ();
450 }
451
452 PlugUIBase::PlugUIBase (boost::shared_ptr<PluginInsert> pi)
453         : insert (pi)
454         , plugin (insert->plugin())
455         , add_button (_("Add"))
456         , save_button (_("Save"))
457         , delete_button (_("Delete"))
458         , reset_button (_("Reset"))
459         , bypass_button (ArdourButton::led_default_elements)
460         , pin_management_button (_("Pinout"))
461         , description_expander (_("Description"))
462         , plugin_analysis_expander (_("Plugin analysis"))
463         , latency_gui (0)
464         , latency_dialog (0)
465         , eqgui (0)
466 {
467         _preset_modified.set_size_request (16, -1);
468         _preset_combo.set_text("(default)");
469         set_tooltip (_preset_combo, _("Presets (if any) for this plugin\n(Both factory and user-created)"));
470         set_tooltip (add_button, _("Save a new preset"));
471         set_tooltip (save_button, _("Save the current preset"));
472         set_tooltip (delete_button, _("Delete the current preset"));
473         set_tooltip (reset_button, _("Reset parameters to default (if no parameters are in automation play mode)"));
474         set_tooltip (pin_management_button, _("Show Plugin Pin Management Dialog"));
475         set_tooltip (bypass_button, _("Disable signal processing by the plugin"));
476         _no_load_preset = 0;
477
478         update_preset_list ();
479         update_preset ();
480
481         add_button.set_name ("generic button");
482         add_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::add_plugin_setting));
483
484         save_button.set_name ("generic button");
485         save_button.signal_clicked.connect(sigc::mem_fun(*this, &PlugUIBase::save_plugin_setting));
486
487         delete_button.set_name ("generic button");
488         delete_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::delete_plugin_setting));
489
490         reset_button.set_name ("generic button");
491         reset_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::reset_plugin_parameters));
492
493         pin_management_button.set_name ("generic button");
494         pin_management_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::manage_pins));
495
496         insert->ActiveChanged.connect (active_connection, invalidator (*this), boost::bind (&PlugUIBase::processor_active_changed, this,  boost::weak_ptr<Processor>(insert)), gui_context());
497
498         bypass_button.set_name ("plugin bypass button");
499         bypass_button.set_text (_("Bypass"));
500         bypass_button.set_active (!pi->enabled ());
501         bypass_button.signal_button_release_event().connect (sigc::mem_fun(*this, &PlugUIBase::bypass_button_release), false);
502         focus_button.add_events (Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
503
504         focus_button.signal_button_release_event().connect (sigc::mem_fun(*this, &PlugUIBase::focus_toggled));
505         focus_button.add_events (Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
506
507         /* these images are not managed, so that we can remove them at will */
508
509         focus_out_image = new Image (get_icon (X_("computer_keyboard")));
510         focus_in_image = new Image (get_icon (X_("computer_keyboard_active")));
511
512         focus_button.add (*focus_out_image);
513
514         set_tooltip (focus_button, string_compose (_("Click to allow the plugin to receive keyboard events that %1 would normally use as a shortcut"), PROGRAM_NAME));
515         set_tooltip (bypass_button, _("Click to enable/disable this plugin"));
516
517         description_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &PlugUIBase::toggle_description));
518         description_expander.set_expanded(false);
519
520         plugin_analysis_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &PlugUIBase::toggle_plugin_analysis));
521         plugin_analysis_expander.set_expanded(false);
522
523         insert->DropReferences.connect (death_connection, invalidator (*this), boost::bind (&PlugUIBase::plugin_going_away, this), gui_context());
524
525         plugin->PresetAdded.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::preset_added_or_removed, this), gui_context ());
526         plugin->PresetRemoved.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::preset_added_or_removed, this), gui_context ());
527         plugin->PresetLoaded.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::update_preset, this), gui_context ());
528         plugin->PresetDirty.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::update_preset_modified, this), gui_context ());
529
530         insert->AutomationStateChanged.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::automation_state_changed, this), gui_context());
531
532         automation_state_changed();
533 }
534
535 PlugUIBase::~PlugUIBase()
536 {
537         delete eqgui;
538         delete latency_gui;
539 }
540
541 void
542 PlugUIBase::plugin_going_away ()
543 {
544         /* drop references to the plugin/insert */
545         insert.reset ();
546         plugin.reset ();
547 }
548
549 void
550 PlugUIBase::set_latency_label ()
551 {
552         samplecnt_t const l = insert->effective_latency ();
553         samplecnt_t const sr = insert->session().sample_rate ();
554
555         string t;
556
557         if (l < sr / 1000) {
558                 t = string_compose (P_("latency (%1 sample)", "latency (%1 samples)", l), l);
559         } else {
560                 t = string_compose (_("latency (%1 ms)"), (float) l / ((float) sr / 1000.0f));
561         }
562
563         latency_button.set_text (t);
564 }
565
566 void
567 PlugUIBase::latency_button_clicked ()
568 {
569         if (!latency_gui) {
570                 latency_gui = new LatencyGUI (*(insert.get()), insert->session().sample_rate(), insert->session().get_block_size());
571                 latency_dialog = new ArdourWindow (_("Edit Latency"));
572                 /* use both keep-above and transient for to try cover as many
573                    different WM's as possible.
574                 */
575                 latency_dialog->set_keep_above (true);
576                 Window* win = dynamic_cast<Window*> (bypass_button.get_toplevel ());
577                 if (win) {
578                         latency_dialog->set_transient_for (*win);
579                 }
580                 latency_dialog->add (*latency_gui);
581                 latency_dialog->signal_hide().connect (sigc::mem_fun (*this, &PlugUIBase::set_latency_label));
582         }
583
584         latency_dialog->show_all ();
585 }
586
587 void
588 PlugUIBase::processor_active_changed (boost::weak_ptr<Processor> weak_p)
589 {
590         ENSURE_GUI_THREAD (*this, &PlugUIBase::processor_active_changed, weak_p);
591         boost::shared_ptr<Processor> p (weak_p.lock());
592
593         if (p) {
594                 bypass_button.set_active (!p->enabled ());
595         }
596 }
597
598 void
599 PlugUIBase::preset_selected (Plugin::PresetRecord preset)
600 {
601         if (_no_load_preset) {
602                 return;
603         }
604         if (!preset.label.empty()) {
605                 insert->load_preset (preset);
606         } else {
607                 // blank selected = no preset
608                 plugin->clear_preset();
609         }
610 }
611
612 #ifdef NO_PLUGIN_STATE
613 static bool seen_saving_message = false;
614
615 static void show_no_plugin_message()
616 {
617         info << string_compose (_("Plugin presets are not supported in this build of %1. Consider paying for a full version"),
618                         PROGRAM_NAME)
619              << endmsg;
620         info << _("To get full access to updates without this limitation\n"
621                   "consider becoming a subscriber for a low cost every month.")
622              << endmsg;
623         info << X_("https://community.ardour.org/s/subscribe")
624              << endmsg;
625         ARDOUR_UI::instance()->popup_error(_("Plugin presets are not supported in this build, see the Log window for more information."));
626 }
627 #endif
628
629 void
630 PlugUIBase::add_plugin_setting ()
631 {
632 #ifndef NO_PLUGIN_STATE
633         NewPluginPresetDialog d (plugin, _("New Preset"));
634
635         switch (d.run ()) {
636         case Gtk::RESPONSE_ACCEPT:
637                 if (d.name().empty()) {
638                         break;
639                 }
640
641                 if (d.replace ()) {
642                         plugin->remove_preset (d.name ());
643                 }
644
645                 Plugin::PresetRecord const r = plugin->save_preset (d.name());
646                 if (!r.uri.empty ()) {
647                         plugin->load_preset (r);
648                 }
649                 break;
650         }
651 #else
652         if (!seen_saving_message) {
653                 seen_saving_message = true;
654                 show_no_plugin_message();
655         }
656 #endif
657 }
658
659 void
660 PlugUIBase::save_plugin_setting ()
661 {
662 #ifndef NO_PLUGIN_STATE
663         string const name = _preset_combo.get_text ();
664         plugin->remove_preset (name);
665         Plugin::PresetRecord const r = plugin->save_preset (name);
666         if (!r.uri.empty ()) {
667                 plugin->load_preset (r);
668         }
669 #else
670         if (!seen_saving_message) {
671                 seen_saving_message = true;
672                 show_no_plugin_message();
673         }
674 #endif
675 }
676
677 void
678 PlugUIBase::delete_plugin_setting ()
679 {
680 #ifndef NO_PLUGIN_STATE
681         plugin->remove_preset (_preset_combo.get_text ());
682 #else
683         if (!seen_saving_message) {
684                 seen_saving_message = true;
685                 show_no_plugin_message();
686         }
687 #endif
688 }
689
690 void
691 PlugUIBase::automation_state_changed ()
692 {
693         reset_button.set_sensitive (insert->can_reset_all_parameters());
694 }
695
696 void
697 PlugUIBase::reset_plugin_parameters ()
698 {
699         insert->reset_parameters_to_default ();
700 }
701
702 void
703 PlugUIBase::manage_pins ()
704 {
705         PluginPinWindowProxy* proxy = insert->pinmgr_proxy ();
706         if (proxy) {
707                 proxy->get (true);
708                 proxy->present ();
709                 proxy->get ()->raise();
710         }
711 }
712
713 bool
714 PlugUIBase::bypass_button_release (GdkEventButton*)
715 {
716         bool view_says_bypassed = (bypass_button.active_state() != 0);
717
718         if (view_says_bypassed != insert->enabled ()) {
719                 insert->enable (view_says_bypassed);
720         }
721
722         return false;
723 }
724
725 bool
726 PlugUIBase::focus_toggled (GdkEventButton*)
727 {
728         if (Keyboard::the_keyboard().some_magic_widget_has_focus()) {
729                 Keyboard::the_keyboard().magic_widget_drop_focus();
730                 focus_button.remove ();
731                 focus_button.add (*focus_out_image);
732                 focus_out_image->show ();
733                 set_tooltip (focus_button, string_compose (_("Click to allow the plugin to receive keyboard events that %1 would normally use as a shortcut"), PROGRAM_NAME));
734                 KeyboardFocused (false);
735         } else {
736                 Keyboard::the_keyboard().magic_widget_grab_focus();
737                 focus_button.remove ();
738                 focus_button.add (*focus_in_image);
739                 focus_in_image->show ();
740                 set_tooltip (focus_button, string_compose (_("Click to allow normal use of %1 keyboard shortcuts"), PROGRAM_NAME));
741                 KeyboardFocused (true);
742         }
743
744         return true;
745 }
746
747 void
748 PlugUIBase::toggle_description()
749 {
750         if (description_expander.get_expanded() &&
751             !description_expander.get_child()) {
752                 const std::string text = plugin->get_docs();
753                 if (text.empty()) {
754                         return;
755                 }
756
757                 Gtk::Label* label = manage(new Gtk::Label(text));
758                 label->set_line_wrap(true);
759                 label->set_line_wrap_mode(Pango::WRAP_WORD);
760                 description_expander.add(*label);
761                 description_expander.show_all();
762         }
763
764         if (!description_expander.get_expanded()) {
765                 const int child_height = description_expander.get_child ()->get_height ();
766
767                 description_expander.remove();
768
769                 Gtk::Window *toplevel = (Gtk::Window*) description_expander.get_ancestor (GTK_TYPE_WINDOW);
770
771                 if (toplevel) {
772                         Gtk::Requisition wr;
773                         toplevel->get_size (wr.width, wr.height);
774                         wr.height -= child_height;
775                         toplevel->resize (wr.width, wr.height);
776                 }
777
778         }
779 }
780
781
782 void
783 PlugUIBase::toggle_plugin_analysis()
784 {
785         if (plugin_analysis_expander.get_expanded() &&
786             !plugin_analysis_expander.get_child()) {
787                 // Create the GUI
788                 if (eqgui == 0) {
789                         eqgui = new PluginEqGui (insert);
790                 }
791
792                 plugin_analysis_expander.add (*eqgui);
793                 plugin_analysis_expander.show_all ();
794                 eqgui->start_listening ();
795         }
796
797         if (!plugin_analysis_expander.get_expanded()) {
798                 // Hide & remove from expander
799                 const int child_height = plugin_analysis_expander.get_child ()->get_height ();
800
801                 eqgui->hide ();
802                 eqgui->stop_listening ();
803                 plugin_analysis_expander.remove();
804
805                 Gtk::Window *toplevel = (Gtk::Window*) plugin_analysis_expander.get_ancestor (GTK_TYPE_WINDOW);
806
807                 if (toplevel) {
808                         Gtk::Requisition wr;
809                         toplevel->get_size (wr.width, wr.height);
810                         wr.height -= child_height;
811                         toplevel->resize (wr.width, wr.height);
812                 }
813         }
814 }
815
816 void
817 PlugUIBase::update_preset_list ()
818 {
819         using namespace Menu_Helpers;
820
821         vector<ARDOUR::Plugin::PresetRecord> presets = plugin->get_presets();
822
823         ++_no_load_preset;
824
825         // Add a menu entry for each preset
826         _preset_combo.clear_items();
827         for (vector<ARDOUR::Plugin::PresetRecord>::const_iterator i = presets.begin(); i != presets.end(); ++i) {
828                 _preset_combo.AddMenuElem(
829                         MenuElem(i->label, sigc::bind(sigc::mem_fun(*this, &PlugUIBase::preset_selected), *i)));
830         }
831
832         // Add an empty entry for un-setting current preset (see preset_selected)
833         Plugin::PresetRecord no_preset;
834         _preset_combo.AddMenuElem(
835                 MenuElem("", sigc::bind(sigc::mem_fun(*this, &PlugUIBase::preset_selected), no_preset)));
836
837         --_no_load_preset;
838 }
839
840 void
841 PlugUIBase::update_preset ()
842 {
843         Plugin::PresetRecord p = plugin->last_preset();
844
845         ++_no_load_preset;
846         if (p.uri.empty()) {
847                 _preset_combo.set_text (_("(none)"));
848         } else {
849                 _preset_combo.set_text (p.label);
850         }
851         --_no_load_preset;
852
853         save_button.set_sensitive (!p.uri.empty() && p.user);
854         delete_button.set_sensitive (!p.uri.empty() && p.user);
855
856         update_preset_modified ();
857 }
858
859 void
860 PlugUIBase::update_preset_modified ()
861 {
862
863         if (plugin->last_preset().uri.empty()) {
864                 _preset_modified.set_text ("");
865                 return;
866         }
867
868         bool const c = plugin->parameter_changed_since_last_preset ();
869         if (_preset_modified.get_text().empty() == c) {
870                 _preset_modified.set_text (c ? "*" : "");
871         }
872 }
873
874 void
875 PlugUIBase::preset_added_or_removed ()
876 {
877         /* Update both the list and the currently-displayed preset */
878         update_preset_list ();
879         update_preset ();
880 }
881