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);
445 gtk_window_propagate_key_event (GTK_WINDOW(gobj()), event);
447 /* don't forward releases */
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 , reset_button (_("Reset"))
470 , bypass_button (ArdourButton::led_default_elements)
471 , pin_management_button (_("Pinout"))
472 , description_expander (_("Description"))
473 , plugin_analysis_expander (_("Plugin analysis"))
474 , cpuload_expander (_("CPU Profile"))
481 _preset_modified.set_size_request (16, -1);
482 _preset_combo.set_text("(default)");
483 set_tooltip (_preset_combo, _("Presets (if any) for this plugin\n(Both factory and user-created)"));
484 set_tooltip (add_button, _("Save a new preset"));
485 set_tooltip (save_button, _("Save the current preset"));
486 set_tooltip (delete_button, _("Delete the current preset"));
487 set_tooltip (reset_button, _("Reset parameters to default (if no parameters are in automation play mode)"));
488 set_tooltip (pin_management_button, _("Show Plugin Pin Management Dialog"));
489 set_tooltip (bypass_button, _("Disable signal processing by the plugin"));
490 set_tooltip (latency_button, _("Edit Plugin Delay/Latency Compensation"));
493 update_preset_list ();
496 latency_button.set_icon (ArdourIcon::LatencyClock);
497 latency_button.add_elements (ArdourButton::Text);
499 add_button.set_name ("generic button");
500 add_button.set_icon (ArdourIcon::PsetAdd);
501 add_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::add_plugin_setting));
503 save_button.set_name ("generic button");
504 save_button.set_icon (ArdourIcon::PsetSave);
505 save_button.signal_clicked.connect(sigc::mem_fun(*this, &PlugUIBase::save_plugin_setting));
507 delete_button.set_name ("generic button");
508 delete_button.set_icon (ArdourIcon::PsetDelete);
509 delete_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::delete_plugin_setting));
511 reset_button.set_name ("generic button");
512 reset_button.set_icon (ArdourIcon::PluginReset);
513 reset_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::reset_plugin_parameters));
515 pin_management_button.set_name ("generic button");
516 pin_management_button.set_icon (ArdourIcon::PluginPinout);
517 pin_management_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::manage_pins));
519 insert->ActiveChanged.connect (active_connection, invalidator (*this), boost::bind (&PlugUIBase::processor_active_changed, this, boost::weak_ptr<Processor>(insert)), gui_context());
521 bypass_button.set_name ("plugin bypass button");
522 bypass_button.set_text (_("Bypass"));
523 bypass_button.set_icon (ArdourIcon::PluginBypass);
524 bypass_button.set_active (!pi->enabled ());
525 bypass_button.signal_button_release_event().connect (sigc::mem_fun(*this, &PlugUIBase::bypass_button_release), false);
526 focus_button.add_events (Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
528 focus_button.signal_button_release_event().connect (sigc::mem_fun(*this, &PlugUIBase::focus_toggled));
529 focus_button.add_events (Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
531 /* these images are not managed, so that we can remove them at will */
533 focus_out_image = new Image (get_icon (X_("computer_keyboard")));
534 focus_in_image = new Image (get_icon (X_("computer_keyboard_active")));
536 focus_button.add (*focus_out_image);
538 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));
539 set_tooltip (bypass_button, _("Click to enable/disable this plugin"));
541 description_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &PlugUIBase::toggle_description));
542 description_expander.set_expanded(false);
544 plugin_analysis_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &PlugUIBase::toggle_plugin_analysis));
545 plugin_analysis_expander.set_expanded(false);
547 cpuload_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &PlugUIBase::toggle_cpuload_display));
548 cpuload_expander.set_expanded(false);
550 insert->DropReferences.connect (death_connection, invalidator (*this), boost::bind (&PlugUIBase::plugin_going_away, this), gui_context());
552 plugin->PresetAdded.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::preset_added_or_removed, this), gui_context ());
553 plugin->PresetRemoved.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::preset_added_or_removed, this), gui_context ());
554 plugin->PresetLoaded.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::update_preset, this), gui_context ());
555 plugin->PresetDirty.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::update_preset_modified, this), gui_context ());
557 insert->AutomationStateChanged.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::automation_state_changed, this), gui_context());
559 insert->LatencyChanged.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::set_latency_label, this), gui_context());
561 automation_state_changed();
564 PlugUIBase::~PlugUIBase()
570 delete latency_dialog;
574 PlugUIBase::plugin_going_away ()
576 /* drop references to the plugin/insert */
582 PlugUIBase::set_latency_label ()
584 samplecnt_t const l = insert->effective_latency ();
585 samplecnt_t const sr = insert->session().sample_rate ();
590 t = string_compose (P_("%1 sample", "%1 samples", l), l);
592 t = string_compose (_("%1 ms"), (float) l / ((float) sr / 1000.0f));
595 latency_button.set_text (t);
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();
644 #ifdef NO_PLUGIN_STATE
645 static bool seen_saving_message = false;
647 static void show_no_plugin_message()
649 info << string_compose (_("Plugin presets are not supported in this build of %1. Consider paying for a full version"),
652 info << _("To get full access to updates without this limitation\n"
653 "consider becoming a subscriber for a low cost every month.")
655 info << X_("https://community.ardour.org/s/subscribe")
657 ARDOUR_UI::instance()->popup_error(_("Plugin presets are not supported in this build, see the Log window for more information."));
662 PlugUIBase::add_plugin_setting ()
664 #ifndef NO_PLUGIN_STATE
665 NewPluginPresetDialog d (plugin, _("New Preset"));
668 case Gtk::RESPONSE_ACCEPT:
669 if (d.name().empty()) {
674 plugin->remove_preset (d.name ());
677 Plugin::PresetRecord const r = plugin->save_preset (d.name());
678 if (!r.uri.empty ()) {
679 plugin->load_preset (r);
684 if (!seen_saving_message) {
685 seen_saving_message = true;
686 show_no_plugin_message();
692 PlugUIBase::save_plugin_setting ()
694 #ifndef NO_PLUGIN_STATE
695 string const name = _preset_combo.get_text ();
696 plugin->remove_preset (name);
697 Plugin::PresetRecord const r = plugin->save_preset (name);
698 if (!r.uri.empty ()) {
699 plugin->load_preset (r);
702 if (!seen_saving_message) {
703 seen_saving_message = true;
704 show_no_plugin_message();
710 PlugUIBase::delete_plugin_setting ()
712 #ifndef NO_PLUGIN_STATE
713 plugin->remove_preset (_preset_combo.get_text ());
715 if (!seen_saving_message) {
716 seen_saving_message = true;
717 show_no_plugin_message();
723 PlugUIBase::automation_state_changed ()
725 reset_button.set_sensitive (insert->can_reset_all_parameters());
729 PlugUIBase::reset_plugin_parameters ()
731 insert->reset_parameters_to_default ();
735 PlugUIBase::manage_pins ()
737 PluginPinWindowProxy* proxy = insert->pinmgr_proxy ();
741 proxy->get ()->raise();
746 PlugUIBase::bypass_button_release (GdkEventButton*)
748 bool view_says_bypassed = (bypass_button.active_state() != 0);
750 if (view_says_bypassed != insert->enabled ()) {
751 insert->enable (view_says_bypassed);
758 PlugUIBase::focus_toggled (GdkEventButton*)
760 if (Keyboard::the_keyboard().some_magic_widget_has_focus()) {
761 Keyboard::the_keyboard().magic_widget_drop_focus();
762 focus_button.remove ();
763 focus_button.add (*focus_out_image);
764 focus_out_image->show ();
765 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));
766 KeyboardFocused (false);
768 Keyboard::the_keyboard().magic_widget_grab_focus();
769 focus_button.remove ();
770 focus_button.add (*focus_in_image);
771 focus_in_image->show ();
772 set_tooltip (focus_button, string_compose (_("Click to allow normal use of %1 keyboard shortcuts"), PROGRAM_NAME));
773 KeyboardFocused (true);
780 PlugUIBase::toggle_description()
782 if (description_expander.get_expanded() &&
783 !description_expander.get_child()) {
784 const std::string text = plugin->get_docs();
789 Gtk::Label* label = manage(new Gtk::Label(text));
790 label->set_line_wrap(true);
791 label->set_line_wrap_mode(Pango::WRAP_WORD);
792 description_expander.add(*label);
793 description_expander.show_all();
796 if (!description_expander.get_expanded()) {
797 const int child_height = description_expander.get_child ()->get_height ();
799 description_expander.remove();
801 Gtk::Window *toplevel = (Gtk::Window*) description_expander.get_ancestor (GTK_TYPE_WINDOW);
805 toplevel->get_size (wr.width, wr.height);
806 wr.height -= child_height;
807 toplevel->resize (wr.width, wr.height);
813 PlugUIBase::toggle_plugin_analysis()
815 if (plugin_analysis_expander.get_expanded() &&
816 !plugin_analysis_expander.get_child()) {
819 eqgui = new PluginEqGui (insert);
822 plugin_analysis_expander.add (*eqgui);
823 plugin_analysis_expander.show_all ();
824 eqgui->start_listening ();
827 if (!plugin_analysis_expander.get_expanded()) {
828 // Hide & remove from expander
829 const int child_height = plugin_analysis_expander.get_child ()->get_height ();
832 eqgui->stop_listening ();
833 plugin_analysis_expander.remove();
835 Gtk::Window *toplevel = (Gtk::Window*) plugin_analysis_expander.get_ancestor (GTK_TYPE_WINDOW);
839 toplevel->get_size (wr.width, wr.height);
840 wr.height -= child_height;
841 toplevel->resize (wr.width, wr.height);
847 PlugUIBase::toggle_cpuload_display()
849 if (cpuload_expander.get_expanded() && !cpuload_expander.get_child()) {
850 if (stats_gui == 0) {
851 stats_gui = new PluginLoadStatsGui (insert);
853 cpuload_expander.add (*stats_gui);
854 cpuload_expander.show_all();
855 stats_gui->start_updating ();
858 if (!cpuload_expander.get_expanded()) {
859 const int child_height = cpuload_expander.get_child ()->get_height ();
862 stats_gui->stop_updating ();
863 cpuload_expander.remove();
865 Gtk::Window *toplevel = (Gtk::Window*) cpuload_expander.get_ancestor (GTK_TYPE_WINDOW);
869 toplevel->get_size (wr.width, wr.height);
870 wr.height -= child_height;
871 toplevel->resize (wr.width, wr.height);
878 PlugUIBase::update_preset_list ()
880 using namespace Menu_Helpers;
882 vector<ARDOUR::Plugin::PresetRecord> presets = plugin->get_presets();
886 // Add a menu entry for each preset
887 _preset_combo.clear_items();
888 for (vector<ARDOUR::Plugin::PresetRecord>::const_iterator i = presets.begin(); i != presets.end(); ++i) {
889 _preset_combo.AddMenuElem(
890 MenuElem(i->label, sigc::bind(sigc::mem_fun(*this, &PlugUIBase::preset_selected), *i)));
893 // Add an empty entry for un-setting current preset (see preset_selected)
894 Plugin::PresetRecord no_preset;
895 _preset_combo.AddMenuElem(
896 MenuElem("", sigc::bind(sigc::mem_fun(*this, &PlugUIBase::preset_selected), no_preset)));
902 PlugUIBase::update_preset ()
904 Plugin::PresetRecord p = plugin->last_preset();
908 _preset_combo.set_text (_("(none)"));
910 _preset_combo.set_text (p.label);
914 delete_button.set_sensitive (!p.uri.empty() && p.user);
915 update_preset_modified ();
919 PlugUIBase::update_preset_modified ()
921 Plugin::PresetRecord p = plugin->last_preset();
924 save_button.set_sensitive (false);
925 _preset_modified.set_text ("");
929 bool const c = plugin->parameter_changed_since_last_preset ();
930 if (_preset_modified.get_text().empty() == c) {
931 _preset_modified.set_text (c ? "*" : "");
933 save_button.set_sensitive (c && p.user);
937 PlugUIBase::preset_added_or_removed ()
939 /* Update both the list and the currently-displayed preset */
940 update_preset_list ();