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"));
492 update_preset_list ();
495 add_button.set_name ("generic button");
496 add_button.set_icon (ArdourIcon::PsetAdd);
497 add_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::add_plugin_setting));
499 save_button.set_name ("generic button");
500 save_button.set_icon (ArdourIcon::PsetSave);
501 save_button.signal_clicked.connect(sigc::mem_fun(*this, &PlugUIBase::save_plugin_setting));
503 delete_button.set_name ("generic button");
504 delete_button.set_icon (ArdourIcon::PsetDelete);
505 delete_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::delete_plugin_setting));
507 reset_button.set_name ("generic button");
508 reset_button.set_icon (ArdourIcon::PluginReset);
509 reset_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::reset_plugin_parameters));
511 pin_management_button.set_name ("generic button");
512 pin_management_button.set_icon (ArdourIcon::PluginPinout);
513 pin_management_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::manage_pins));
515 insert->ActiveChanged.connect (active_connection, invalidator (*this), boost::bind (&PlugUIBase::processor_active_changed, this, boost::weak_ptr<Processor>(insert)), gui_context());
517 bypass_button.set_name ("plugin bypass button");
518 bypass_button.set_text (_("Bypass"));
519 bypass_button.set_icon (ArdourIcon::PluginBypass);
520 bypass_button.set_active (!pi->enabled ());
521 bypass_button.signal_button_release_event().connect (sigc::mem_fun(*this, &PlugUIBase::bypass_button_release), false);
522 focus_button.add_events (Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
524 focus_button.signal_button_release_event().connect (sigc::mem_fun(*this, &PlugUIBase::focus_toggled));
525 focus_button.add_events (Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
527 /* these images are not managed, so that we can remove them at will */
529 focus_out_image = new Image (get_icon (X_("computer_keyboard")));
530 focus_in_image = new Image (get_icon (X_("computer_keyboard_active")));
532 focus_button.add (*focus_out_image);
534 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));
535 set_tooltip (bypass_button, _("Click to enable/disable this plugin"));
537 description_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &PlugUIBase::toggle_description));
538 description_expander.set_expanded(false);
540 plugin_analysis_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &PlugUIBase::toggle_plugin_analysis));
541 plugin_analysis_expander.set_expanded(false);
543 cpuload_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &PlugUIBase::toggle_cpuload_display));
544 cpuload_expander.set_expanded(false);
546 insert->DropReferences.connect (death_connection, invalidator (*this), boost::bind (&PlugUIBase::plugin_going_away, this), gui_context());
548 plugin->PresetAdded.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::preset_added_or_removed, this), gui_context ());
549 plugin->PresetRemoved.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::preset_added_or_removed, this), gui_context ());
550 plugin->PresetLoaded.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::update_preset, this), gui_context ());
551 plugin->PresetDirty.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::update_preset_modified, this), gui_context ());
553 insert->AutomationStateChanged.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::automation_state_changed, this), gui_context());
555 insert->LatencyChanged.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::set_latency_label, this), gui_context());
557 automation_state_changed();
560 PlugUIBase::~PlugUIBase()
566 delete latency_dialog;
570 PlugUIBase::plugin_going_away ()
572 /* drop references to the plugin/insert */
578 PlugUIBase::set_latency_label ()
580 samplecnt_t const l = insert->effective_latency ();
581 samplecnt_t const sr = insert->session().sample_rate ();
586 t = string_compose (P_("latency (%1 sample)", "latency (%1 samples)", l), l);
588 t = string_compose (_("latency (%1 ms)"), (float) l / ((float) sr / 1000.0f));
591 latency_button.set_text (t);
595 PlugUIBase::latency_button_clicked ()
598 latency_gui = new LatencyGUI (*(insert.get()), insert->session().sample_rate(), insert->session().get_block_size());
599 latency_dialog = new ArdourWindow (_("Edit Latency"));
600 /* use both keep-above and transient for to try cover as many
601 different WM's as possible.
603 latency_dialog->set_keep_above (true);
604 Window* win = dynamic_cast<Window*> (bypass_button.get_toplevel ());
606 latency_dialog->set_transient_for (*win);
608 latency_dialog->add (*latency_gui);
611 latency_gui->refresh ();
612 latency_dialog->show_all ();
616 PlugUIBase::processor_active_changed (boost::weak_ptr<Processor> weak_p)
618 ENSURE_GUI_THREAD (*this, &PlugUIBase::processor_active_changed, weak_p);
619 boost::shared_ptr<Processor> p (weak_p.lock());
622 bypass_button.set_active (!p->enabled ());
627 PlugUIBase::preset_selected (Plugin::PresetRecord preset)
629 if (_no_load_preset) {
632 if (!preset.label.empty()) {
633 insert->load_preset (preset);
635 // blank selected = no preset
636 plugin->clear_preset();
640 #ifdef NO_PLUGIN_STATE
641 static bool seen_saving_message = false;
643 static void show_no_plugin_message()
645 info << string_compose (_("Plugin presets are not supported in this build of %1. Consider paying for a full version"),
648 info << _("To get full access to updates without this limitation\n"
649 "consider becoming a subscriber for a low cost every month.")
651 info << X_("https://community.ardour.org/s/subscribe")
653 ARDOUR_UI::instance()->popup_error(_("Plugin presets are not supported in this build, see the Log window for more information."));
658 PlugUIBase::add_plugin_setting ()
660 #ifndef NO_PLUGIN_STATE
661 NewPluginPresetDialog d (plugin, _("New Preset"));
664 case Gtk::RESPONSE_ACCEPT:
665 if (d.name().empty()) {
670 plugin->remove_preset (d.name ());
673 Plugin::PresetRecord const r = plugin->save_preset (d.name());
674 if (!r.uri.empty ()) {
675 plugin->load_preset (r);
680 if (!seen_saving_message) {
681 seen_saving_message = true;
682 show_no_plugin_message();
688 PlugUIBase::save_plugin_setting ()
690 #ifndef NO_PLUGIN_STATE
691 string const name = _preset_combo.get_text ();
692 plugin->remove_preset (name);
693 Plugin::PresetRecord const r = plugin->save_preset (name);
694 if (!r.uri.empty ()) {
695 plugin->load_preset (r);
698 if (!seen_saving_message) {
699 seen_saving_message = true;
700 show_no_plugin_message();
706 PlugUIBase::delete_plugin_setting ()
708 #ifndef NO_PLUGIN_STATE
709 plugin->remove_preset (_preset_combo.get_text ());
711 if (!seen_saving_message) {
712 seen_saving_message = true;
713 show_no_plugin_message();
719 PlugUIBase::automation_state_changed ()
721 reset_button.set_sensitive (insert->can_reset_all_parameters());
725 PlugUIBase::reset_plugin_parameters ()
727 insert->reset_parameters_to_default ();
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 ();