2 * Copyright (C) 2005-2006 Nick Mainsbridge <mainsbridge@gmail.com>
3 * Copyright (C) 2005-2017 Paul Davis <paul@linuxaudiosystems.com>
4 * Copyright (C) 2005 Taybin Rutkin <taybin@taybin.com>
5 * Copyright (C) 2006-2009 Sampo Savolainen <v2@iki.fi>
6 * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
7 * Copyright (C) 2009-2011 Carl Hetherington <carl@carlh.net>
8 * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
9 * Copyright (C) 2013-2018 John Emmas <john@creativepost.co.uk>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "gtk2ardour-config.h"
35 #include "pbd/stl_delete.h"
36 #include "pbd/xml++.h"
37 #include "pbd/failed_constructor.h"
39 #include "gtkmm/widget.h"
40 #include "gtkmm/box.h"
42 #include "gtkmm2ext/utils.h"
43 #include "gtkmm2ext/doi.h"
44 #include "gtkmm2ext/application.h"
46 #include "widgets/tooltips.h"
47 #include "widgets/fastmeter.h"
49 #include "ardour/session.h"
50 #include "ardour/plugin.h"
51 #include "ardour/plugin_insert.h"
52 #include "ardour/ladspa_plugin.h"
53 #ifdef WINDOWS_VST_SUPPORT
54 #include "ardour/windows_vst_plugin.h"
55 #include "windows_vst_plugin_ui.h"
58 #include "ardour/lxvst_plugin.h"
59 #include "lxvst_plugin_ui.h"
62 #include "ardour/mac_vst_plugin.h"
63 #include "vst_plugin_ui.h"
66 #include "ardour/lv2_plugin.h"
67 #include "lv2_plugin_ui.h"
70 #include "ardour_window.h"
71 #include "ardour_ui.h"
72 #include "plugin_ui.h"
74 #include "gui_thread.h"
75 #include "public_editor.h"
76 #include "processor_box.h"
78 #include "latency_gui.h"
79 #include "plugin_dspload_ui.h"
80 #include "plugin_eq_gui.h"
81 #include "plugin_presets_ui.h"
83 #include "new_plugin_preset_dialog.h"
88 using namespace ARDOUR;
89 using namespace ARDOUR_UI_UTILS;
90 using namespace ArdourWidgets;
92 using namespace Gtkmm2ext;
96 PluginUIWindow::PluginUIWindow (
97 boost::shared_ptr<PluginInsert> insert,
100 : ArdourWindow (string())
101 , was_visible (false)
102 , _keyboard_focused (false)
103 #ifdef AUDIOUNIT_SUPPORT
104 , pre_deactivate_x (-1)
105 , pre_deactivate_y (-1)
109 bool have_gui = false;
110 Label* label = manage (new Label());
111 label->set_markup ("<b>THIS IS THE PLUGIN UI</b>");
113 if (editor && insert->plugin()->has_editor()) {
114 switch (insert->type()) {
115 case ARDOUR::Windows_VST:
116 have_gui = create_windows_vst_editor (insert);
120 have_gui = create_lxvst_editor (insert);
124 have_gui = create_mac_vst_editor (insert);
127 case ARDOUR::AudioUnit:
128 have_gui = create_audiounit_editor (insert);
132 error << _("Eh? LADSPA plugins don't have editors!") << endmsg;
136 have_gui = create_lv2_editor (insert);
140 #ifndef WINDOWS_VST_SUPPORT
141 error << string_compose (_("unknown type of editor-supplying plugin (note: no VST support in this version of %1)"), PROGRAM_NAME)
144 error << _("unknown type of editor-supplying plugin")
147 throw failed_constructor ();
153 GenericPluginUI* pu = new GenericPluginUI (insert, scrollable);
156 _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
158 set_wmclass (X_("ardour_plugin_editor"), PROGRAM_NAME);
160 signal_map_event().connect (sigc::mem_fun (*pu, &GenericPluginUI::start_updating));
161 signal_unmap_event().connect (sigc::mem_fun (*pu, &GenericPluginUI::stop_updating));
164 set_name ("PluginEditor");
165 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
167 insert->DropReferences.connect (death_connection, invalidator (*this), boost::bind (&PluginUIWindow::plugin_going_away, this), gui_context());
169 gint h = _pluginui->get_preferred_height ();
170 gint w = _pluginui->get_preferred_width ();
173 if (h > 600) h = 600;
176 set_border_width (0);
177 set_default_size (w, h);
178 set_resizable (_pluginui->resizable());
181 PluginUIWindow::~PluginUIWindow ()
184 cerr << "PluginWindow deleted for " << this << endl;
190 PluginUIWindow::on_show ()
192 set_role("plugin_ui");
195 _pluginui->update_preset_list ();
196 _pluginui->update_preset ();
200 #if defined (HAVE_AUDIOUNITS) && defined(__APPLE__)
201 if (pre_deactivate_x >= 0) {
202 move (pre_deactivate_x, pre_deactivate_y);
206 if (_pluginui->on_window_show (_title)) {
213 PluginUIWindow::on_hide ()
215 #if defined (HAVE_AUDIOUNITS) && defined(__APPLE__)
216 get_position (pre_deactivate_x, pre_deactivate_y);
222 _pluginui->on_window_hide ();
227 PluginUIWindow::set_title(const std::string& title)
229 Gtk::Window::set_title(title);
234 #ifdef WINDOWS_VST_SUPPORT
235 PluginUIWindow::create_windows_vst_editor(boost::shared_ptr<PluginInsert> insert)
237 PluginUIWindow::create_windows_vst_editor(boost::shared_ptr<PluginInsert>)
240 #ifndef WINDOWS_VST_SUPPORT
244 boost::shared_ptr<WindowsVSTPlugin> vp;
246 if ((vp = boost::dynamic_pointer_cast<WindowsVSTPlugin> (insert->plugin())) == 0) {
247 error << string_compose (_("unknown type of editor-supplying plugin (note: no VST support in this version of %1)"), PROGRAM_NAME)
249 throw failed_constructor ();
251 WindowsVSTPluginUI* vpu = new WindowsVSTPluginUI (insert, vp, GTK_WIDGET(this->gobj()));
254 _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
256 vpu->package (*this);
265 PluginUIWindow::create_lxvst_editor(boost::shared_ptr<PluginInsert> insert)
267 PluginUIWindow::create_lxvst_editor(boost::shared_ptr<PluginInsert>)
270 #ifndef LXVST_SUPPORT
274 boost::shared_ptr<LXVSTPlugin> lxvp;
276 if ((lxvp = boost::dynamic_pointer_cast<LXVSTPlugin> (insert->plugin())) == 0) {
277 error << string_compose (_("unknown type of editor-supplying plugin (note: no linuxVST support in this version of %1)"), PROGRAM_NAME)
279 throw failed_constructor ();
281 LXVSTPluginUI* lxvpu = new LXVSTPluginUI (insert, lxvp);
284 _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
286 lxvpu->package (*this);
294 #ifdef MACVST_SUPPORT
295 PluginUIWindow::create_mac_vst_editor (boost::shared_ptr<PluginInsert> insert)
297 PluginUIWindow::create_mac_vst_editor (boost::shared_ptr<PluginInsert>)
300 #ifndef MACVST_SUPPORT
303 boost::shared_ptr<MacVSTPlugin> mvst;
304 if ((mvst = boost::dynamic_pointer_cast<MacVSTPlugin> (insert->plugin())) == 0) {
305 error << string_compose (_("unknown type of editor-supplying plugin (note: no MacVST support in this version of %1)"), PROGRAM_NAME)
307 throw failed_constructor ();
309 VSTPluginUI* vpu = create_mac_vst_gui (insert);
311 _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
313 vpu->package (*this);
315 Application::instance()->ActivationChanged.connect (mem_fun (*this, &PluginUIWindow::app_activated));
323 #ifdef AUDIOUNIT_SUPPORT
324 PluginUIWindow::create_audiounit_editor (boost::shared_ptr<PluginInsert> insert)
326 PluginUIWindow::create_audiounit_editor (boost::shared_ptr<PluginInsert>)
329 #ifndef AUDIOUNIT_SUPPORT
333 _pluginui = create_au_gui (insert, &box);
334 _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
337 Application::instance()->ActivationChanged.connect (mem_fun (*this, &PluginUIWindow::app_activated));
345 PluginUIWindow::app_activated (bool yn)
347 PluginUIWindow::app_activated (bool)
350 #ifdef AUDIOUNIT_SUPPORT
354 _pluginui->activate ();
355 if (pre_deactivate_x >= 0) {
356 move (pre_deactivate_x, pre_deactivate_y);
362 was_visible = is_visible();
363 get_position (pre_deactivate_x, pre_deactivate_y);
365 _pluginui->deactivate ();
372 PluginUIWindow::create_lv2_editor(boost::shared_ptr<PluginInsert> insert)
375 boost::shared_ptr<LV2Plugin> vp;
377 if ((vp = boost::dynamic_pointer_cast<LV2Plugin> (insert->plugin())) == 0) {
378 error << _("create_lv2_editor called on non-LV2 plugin") << endmsg;
379 throw failed_constructor ();
381 LV2PluginUI* lpu = new LV2PluginUI (insert, vp);
384 lpu->package (*this);
385 _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
395 PluginUIWindow::keyboard_focused (bool yn)
397 _keyboard_focused = yn;
401 PluginUIWindow::on_key_press_event (GdkEventKey* event)
403 if (_keyboard_focused) {
405 _pluginui->grab_focus();
406 if (_pluginui->non_gtk_gui()) {
407 _pluginui->forward_key_event (event);
409 return relay_key_press (event, this);
414 /* for us to be getting key press events, there really
415 MUST be a _pluginui, but just to be safe, check ...
419 _pluginui->grab_focus();
420 if (_pluginui->non_gtk_gui()) {
421 /* pass main window as the window for the event
422 to be handled in, not this one, because there are
423 no widgets in this window that we want to have
426 return relay_key_press (event, &ARDOUR_UI::instance()->main_window());
428 return relay_key_press (event, this);
436 PluginUIWindow::on_key_release_event (GdkEventKey *event)
438 if (_keyboard_focused) {
440 if (_pluginui->non_gtk_gui()) {
441 _pluginui->forward_key_event (event);
446 gtk_window_propagate_key_event (GTK_WINDOW(gobj()), event);
448 return relay_key_press (event, this);
452 PluginUIWindow::plugin_going_away ()
454 ENSURE_GUI_THREAD (*this, &PluginUIWindow::plugin_going_away)
457 _pluginui->stop_updating(0);
460 death_connection.disconnect ();
463 PlugUIBase::PlugUIBase (boost::shared_ptr<PluginInsert> pi)
465 , plugin (insert->plugin())
466 , add_button (_("Add"))
467 , save_button (_("Save"))
468 , delete_button (_("Delete"))
469 , preset_browser_button (_("Preset Browser"))
470 , reset_button (_("Reset"))
471 , bypass_button (ArdourButton::led_default_elements)
472 , pin_management_button (_("Pinout"))
473 , description_expander (_("Description"))
474 , plugin_analysis_expander (_("Plugin analysis"))
475 , cpuload_expander (_("CPU Profile"))
483 _preset_modified.set_size_request (16, -1);
484 _preset_combo.set_text("(default)");
485 set_tooltip (_preset_combo, _("Presets (if any) for this plugin\n(Both factory and user-created)"));
486 set_tooltip (add_button, _("Save a new preset"));
487 set_tooltip (save_button, _("Save the current preset"));
488 set_tooltip (delete_button, _("Delete the current preset"));
489 set_tooltip (preset_browser_button, _("Show Preset Browser Dialog"));
490 set_tooltip (reset_button, _("Reset parameters to default (if no parameters are in automation play mode)"));
491 set_tooltip (pin_management_button, _("Show Plugin Pin Management Dialog"));
492 set_tooltip (bypass_button, _("Disable signal processing by the plugin"));
493 set_tooltip (latency_button, _("Edit Plugin Delay/Latency Compensation"));
496 update_preset_list ();
499 latency_button.set_icon (ArdourIcon::LatencyClock);
500 latency_button.add_elements (ArdourButton::Text);
502 add_button.set_name ("generic button");
503 add_button.set_icon (ArdourIcon::PsetAdd);
504 add_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::add_plugin_setting));
506 save_button.set_name ("generic button");
507 save_button.set_icon (ArdourIcon::PsetSave);
508 save_button.signal_clicked.connect(sigc::mem_fun(*this, &PlugUIBase::save_plugin_setting));
510 delete_button.set_name ("generic button");
511 delete_button.set_icon (ArdourIcon::PsetDelete);
512 delete_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::delete_plugin_setting));
514 preset_browser_button.set_name ("generic button");
515 preset_browser_button.set_icon (ArdourIcon::PsetBrowse);
516 preset_browser_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::browse_presets));
518 reset_button.set_name ("generic button");
519 reset_button.set_icon (ArdourIcon::PluginReset);
520 reset_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::reset_plugin_parameters));
522 pin_management_button.set_name ("generic button");
523 pin_management_button.set_icon (ArdourIcon::PluginPinout);
524 pin_management_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::manage_pins));
526 insert->ActiveChanged.connect (active_connection, invalidator (*this), boost::bind (&PlugUIBase::processor_active_changed, this, boost::weak_ptr<Processor>(insert)), gui_context());
528 bypass_button.set_name ("plugin bypass button");
529 bypass_button.set_text (_("Bypass"));
530 bypass_button.set_icon (ArdourIcon::PluginBypass);
531 bypass_button.set_active (!pi->enabled ());
532 bypass_button.signal_button_release_event().connect (sigc::mem_fun(*this, &PlugUIBase::bypass_button_release), false);
533 focus_button.add_events (Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
535 focus_button.signal_button_release_event().connect (sigc::mem_fun(*this, &PlugUIBase::focus_toggled));
536 focus_button.add_events (Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
538 /* these images are not managed, so that we can remove them at will */
540 focus_out_image = new Image (get_icon (X_("computer_keyboard")));
541 focus_in_image = new Image (get_icon (X_("computer_keyboard_active")));
543 focus_button.add (*focus_out_image);
545 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));
546 set_tooltip (bypass_button, _("Click to enable/disable this plugin"));
548 description_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &PlugUIBase::toggle_description));
549 description_expander.set_expanded(false);
551 plugin_analysis_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &PlugUIBase::toggle_plugin_analysis));
552 plugin_analysis_expander.set_expanded(false);
554 cpuload_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &PlugUIBase::toggle_cpuload_display));
555 cpuload_expander.set_expanded(false);
557 insert->DropReferences.connect (death_connection, invalidator (*this), boost::bind (&PlugUIBase::plugin_going_away, this), gui_context());
559 plugin->PresetAdded.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::preset_added_or_removed, this), gui_context ());
560 plugin->PresetRemoved.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::preset_added_or_removed, this), gui_context ());
561 plugin->PresetLoaded.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::update_preset, this), gui_context ());
562 plugin->PresetDirty.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::update_preset_modified, this), gui_context ());
564 insert->AutomationStateChanged.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::automation_state_changed, this), gui_context());
566 insert->LatencyChanged.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::set_latency_label, this), gui_context());
568 automation_state_changed();
571 PlugUIBase::~PlugUIBase()
577 delete latency_dialog;
578 delete preset_dialog;
582 PlugUIBase::plugin_going_away ()
584 /* drop references to the plugin/insert */
590 PlugUIBase::set_latency_label ()
592 samplecnt_t const l = insert->effective_latency ();
593 float const sr = insert->session().sample_rate ();
595 latency_button.set_text (samples_as_time_string (l, sr, true));
599 PlugUIBase::latency_button_clicked ()
602 latency_gui = new LatencyGUI (*(insert.get()), insert->session().sample_rate(), insert->session().get_block_size());
603 latency_dialog = new ArdourWindow (_("Edit Latency"));
604 /* use both keep-above and transient for to try cover as many
605 different WM's as possible.
607 latency_dialog->set_keep_above (true);
608 Window* win = dynamic_cast<Window*> (bypass_button.get_toplevel ());
610 latency_dialog->set_transient_for (*win);
612 latency_dialog->add (*latency_gui);
615 latency_gui->refresh ();
616 latency_dialog->show_all ();
620 PlugUIBase::processor_active_changed (boost::weak_ptr<Processor> weak_p)
622 ENSURE_GUI_THREAD (*this, &PlugUIBase::processor_active_changed, weak_p);
623 boost::shared_ptr<Processor> p (weak_p.lock());
626 bypass_button.set_active (!p->enabled ());
631 PlugUIBase::preset_selected (Plugin::PresetRecord preset)
633 if (_no_load_preset) {
636 if (!preset.label.empty()) {
637 insert->load_preset (preset);
639 // blank selected = no preset
640 plugin->clear_preset();
645 PlugUIBase::add_plugin_setting ()
647 NewPluginPresetDialog d (plugin, _("New Preset"));
650 case Gtk::RESPONSE_ACCEPT:
651 if (d.name().empty()) {
656 plugin->remove_preset (d.name ());
659 Plugin::PresetRecord const r = plugin->save_preset (d.name());
660 if (!r.uri.empty ()) {
661 plugin->load_preset (r);
668 PlugUIBase::save_plugin_setting ()
670 string const name = _preset_combo.get_text ();
671 plugin->remove_preset (name);
672 Plugin::PresetRecord const r = plugin->save_preset (name);
673 if (!r.uri.empty ()) {
674 plugin->load_preset (r);
679 PlugUIBase::delete_plugin_setting ()
681 plugin->remove_preset (_preset_combo.get_text ());
685 PlugUIBase::automation_state_changed ()
687 reset_button.set_sensitive (insert->can_reset_all_parameters());
691 PlugUIBase::reset_plugin_parameters ()
693 insert->reset_parameters_to_default ();
697 PlugUIBase::has_descriptive_presets () const
699 std::vector<Plugin::PresetRecord> presets = insert->plugin()->get_presets();
700 for (std::vector<Plugin::PresetRecord>::const_iterator i = presets.begin(); i != presets.end(); ++i) {
701 if (i->valid && !i->description.empty()) {
709 PlugUIBase::browse_presets ()
711 if (!preset_dialog) {
713 /* Do not allow custom window, if preset_gui is used.
714 * e.g. generic-plugin UI.
718 preset_dialog = new ArdourWindow (_("Select Preset"));
719 preset_dialog->set_keep_above (true);
720 Window* win = dynamic_cast<Window*> (preset_browser_button.get_toplevel ());
722 preset_dialog->set_transient_for (*win);
724 preset_gui = new PluginPresetsUI (insert);
725 preset_dialog->add (*preset_gui);
727 preset_dialog->show_all ();
731 PlugUIBase::manage_pins ()
733 PluginPinWindowProxy* proxy = insert->pinmgr_proxy ();
737 proxy->get ()->raise();
742 PlugUIBase::bypass_button_release (GdkEventButton*)
744 bool view_says_bypassed = (bypass_button.active_state() != 0);
746 if (view_says_bypassed != insert->enabled ()) {
747 insert->enable (view_says_bypassed);
754 PlugUIBase::focus_toggled (GdkEventButton*)
756 if (Keyboard::the_keyboard().some_magic_widget_has_focus()) {
757 Keyboard::the_keyboard().magic_widget_drop_focus();
758 focus_button.remove ();
759 focus_button.add (*focus_out_image);
760 focus_out_image->show ();
761 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));
762 KeyboardFocused (false);
764 Keyboard::the_keyboard().magic_widget_grab_focus();
765 focus_button.remove ();
766 focus_button.add (*focus_in_image);
767 focus_in_image->show ();
768 set_tooltip (focus_button, string_compose (_("Click to allow normal use of %1 keyboard shortcuts"), PROGRAM_NAME));
769 KeyboardFocused (true);
776 PlugUIBase::toggle_description()
778 if (description_expander.get_expanded() &&
779 !description_expander.get_child()) {
780 const std::string text = plugin->get_docs();
785 Gtk::Label* label = manage(new Gtk::Label(text));
786 label->set_line_wrap(true);
787 label->set_line_wrap_mode(Pango::WRAP_WORD);
788 description_expander.add(*label);
789 description_expander.show_all();
792 if (!description_expander.get_expanded()) {
793 const int child_height = description_expander.get_child ()->get_height ();
795 description_expander.remove();
797 Gtk::Window *toplevel = (Gtk::Window*) description_expander.get_ancestor (GTK_TYPE_WINDOW);
801 toplevel->get_size (wr.width, wr.height);
802 wr.height -= child_height;
803 toplevel->resize (wr.width, wr.height);
809 PlugUIBase::toggle_plugin_analysis()
811 if (plugin_analysis_expander.get_expanded() &&
812 !plugin_analysis_expander.get_child()) {
815 eqgui = new PluginEqGui (insert);
818 plugin_analysis_expander.add (*eqgui);
819 plugin_analysis_expander.show_all ();
820 eqgui->start_listening ();
823 if (!plugin_analysis_expander.get_expanded()) {
824 // Hide & remove from expander
825 const int child_height = plugin_analysis_expander.get_child ()->get_height ();
828 eqgui->stop_listening ();
829 plugin_analysis_expander.remove();
831 Gtk::Window *toplevel = (Gtk::Window*) plugin_analysis_expander.get_ancestor (GTK_TYPE_WINDOW);
835 toplevel->get_size (wr.width, wr.height);
836 wr.height -= child_height;
837 toplevel->resize (wr.width, wr.height);
843 PlugUIBase::toggle_cpuload_display()
845 if (cpuload_expander.get_expanded() && !cpuload_expander.get_child()) {
846 if (stats_gui == 0) {
847 stats_gui = new PluginLoadStatsGui (insert);
849 cpuload_expander.add (*stats_gui);
850 cpuload_expander.show_all();
851 stats_gui->start_updating ();
854 if (!cpuload_expander.get_expanded()) {
855 const int child_height = cpuload_expander.get_child ()->get_height ();
858 stats_gui->stop_updating ();
859 cpuload_expander.remove();
861 Gtk::Window *toplevel = (Gtk::Window*) cpuload_expander.get_ancestor (GTK_TYPE_WINDOW);
865 toplevel->get_size (wr.width, wr.height);
866 wr.height -= child_height;
867 toplevel->resize (wr.width, wr.height);
874 PlugUIBase::update_preset_list ()
876 using namespace Menu_Helpers;
878 vector<ARDOUR::Plugin::PresetRecord> presets = plugin->get_presets();
882 // Add a menu entry for each preset
883 _preset_combo.clear_items();
884 for (vector<ARDOUR::Plugin::PresetRecord>::const_iterator i = presets.begin(); i != presets.end(); ++i) {
885 _preset_combo.AddMenuElem(
886 MenuElem(i->label, sigc::bind(sigc::mem_fun(*this, &PlugUIBase::preset_selected), *i)));
889 // Add an empty entry for un-setting current preset (see preset_selected)
890 Plugin::PresetRecord no_preset;
891 _preset_combo.AddMenuElem(
892 MenuElem("", sigc::bind(sigc::mem_fun(*this, &PlugUIBase::preset_selected), no_preset)));
898 PlugUIBase::update_preset ()
900 Plugin::PresetRecord p = plugin->last_preset();
904 _preset_combo.set_text (_("(none)"));
906 _preset_combo.set_text (p.label);
910 delete_button.set_sensitive (!p.uri.empty() && p.user);
911 update_preset_modified ();
915 PlugUIBase::update_preset_modified ()
917 Plugin::PresetRecord p = plugin->last_preset();
920 save_button.set_sensitive (false);
921 _preset_modified.set_text ("");
925 bool const c = plugin->parameter_changed_since_last_preset ();
926 if (_preset_modified.get_text().empty() == c) {
927 _preset_modified.set_text (c ? "*" : "");
929 save_button.set_sensitive (c && p.user);
933 PlugUIBase::preset_added_or_removed ()
935 /* Update both the list and the currently-displayed preset */
936 update_preset_list ();