2 Copyright (C) 2000 Paul Davis
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.
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.
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.
21 #include "gtk2ardour-config.h"
29 #include "pbd/stl_delete.h"
30 #include "pbd/xml++.h"
31 #include "pbd/failed_constructor.h"
33 #include "gtkmm/widget.h"
34 #include "gtkmm/box.h"
36 #include "gtkmm2ext/utils.h"
37 #include "gtkmm2ext/doi.h"
38 #include "gtkmm2ext/application.h"
40 #include "widgets/tooltips.h"
41 #include "widgets/fastmeter.h"
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"
52 #include "ardour/lxvst_plugin.h"
53 #include "lxvst_plugin_ui.h"
56 #include "ardour/mac_vst_plugin.h"
57 #include "vst_plugin_ui.h"
60 #include "ardour/lv2_plugin.h"
61 #include "lv2_plugin_ui.h"
64 #include "ardour_window.h"
65 #include "ardour_ui.h"
66 #include "plugin_ui.h"
68 #include "gui_thread.h"
69 #include "public_editor.h"
70 #include "processor_box.h"
72 #include "latency_gui.h"
73 #include "plugin_eq_gui.h"
75 #include "new_plugin_preset_dialog.h"
80 using namespace ARDOUR;
81 using namespace ARDOUR_UI_UTILS;
82 using namespace ArdourWidgets;
84 using namespace Gtkmm2ext;
87 PluginUIWindow::PluginUIWindow (
88 boost::shared_ptr<PluginInsert> insert,
91 : ArdourWindow (string())
93 , _keyboard_focused (false)
94 #ifdef AUDIOUNIT_SUPPORT
95 , pre_deactivate_x (-1)
96 , pre_deactivate_y (-1)
100 bool have_gui = false;
101 Label* label = manage (new Label());
102 label->set_markup ("<b>THIS IS THE PLUGIN UI</b>");
104 if (editor && insert->plugin()->has_editor()) {
105 switch (insert->type()) {
106 case ARDOUR::Windows_VST:
107 have_gui = create_windows_vst_editor (insert);
111 have_gui = create_lxvst_editor (insert);
115 have_gui = create_mac_vst_editor (insert);
118 case ARDOUR::AudioUnit:
119 have_gui = create_audiounit_editor (insert);
123 error << _("Eh? LADSPA plugins don't have editors!") << endmsg;
127 have_gui = create_lv2_editor (insert);
131 #ifndef WINDOWS_VST_SUPPORT
132 error << string_compose (_("unknown type of editor-supplying plugin (note: no VST support in this version of %1)"), PROGRAM_NAME)
135 error << _("unknown type of editor-supplying plugin")
138 throw failed_constructor ();
144 GenericPluginUI* pu = new GenericPluginUI (insert, scrollable);
147 _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
149 set_wmclass (X_("ardour_plugin_editor"), PROGRAM_NAME);
151 signal_map_event().connect (sigc::mem_fun (*pu, &GenericPluginUI::start_updating));
152 signal_unmap_event().connect (sigc::mem_fun (*pu, &GenericPluginUI::stop_updating));
155 set_name ("PluginEditor");
156 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
158 insert->DropReferences.connect (death_connection, invalidator (*this), boost::bind (&PluginUIWindow::plugin_going_away, this), gui_context());
160 gint h = _pluginui->get_preferred_height ();
161 gint w = _pluginui->get_preferred_width ();
164 if (h > 600) h = 600;
167 set_default_size (w, h);
168 set_resizable (_pluginui->resizable());
171 PluginUIWindow::~PluginUIWindow ()
174 cerr << "PluginWindow deleted for " << this << endl;
180 PluginUIWindow::on_show ()
182 set_role("plugin_ui");
185 _pluginui->update_preset_list ();
186 _pluginui->update_preset ();
190 #if defined (HAVE_AUDIOUNITS) && defined(__APPLE__)
191 if (pre_deactivate_x >= 0) {
192 move (pre_deactivate_x, pre_deactivate_y);
196 if (_pluginui->on_window_show (_title)) {
203 PluginUIWindow::on_hide ()
205 #if defined (HAVE_AUDIOUNITS) && defined(__APPLE__)
206 get_position (pre_deactivate_x, pre_deactivate_y);
212 _pluginui->on_window_hide ();
217 PluginUIWindow::set_title(const std::string& title)
219 Gtk::Window::set_title(title);
224 #ifdef WINDOWS_VST_SUPPORT
225 PluginUIWindow::create_windows_vst_editor(boost::shared_ptr<PluginInsert> insert)
227 PluginUIWindow::create_windows_vst_editor(boost::shared_ptr<PluginInsert>)
230 #ifndef WINDOWS_VST_SUPPORT
234 boost::shared_ptr<WindowsVSTPlugin> vp;
236 if ((vp = boost::dynamic_pointer_cast<WindowsVSTPlugin> (insert->plugin())) == 0) {
237 error << string_compose (_("unknown type of editor-supplying plugin (note: no VST support in this version of %1)"), PROGRAM_NAME)
239 throw failed_constructor ();
241 WindowsVSTPluginUI* vpu = new WindowsVSTPluginUI (insert, vp, GTK_WIDGET(this->gobj()));
244 _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
246 vpu->package (*this);
255 PluginUIWindow::create_lxvst_editor(boost::shared_ptr<PluginInsert> insert)
257 PluginUIWindow::create_lxvst_editor(boost::shared_ptr<PluginInsert>)
260 #ifndef LXVST_SUPPORT
264 boost::shared_ptr<LXVSTPlugin> lxvp;
266 if ((lxvp = boost::dynamic_pointer_cast<LXVSTPlugin> (insert->plugin())) == 0) {
267 error << string_compose (_("unknown type of editor-supplying plugin (note: no linuxVST support in this version of %1)"), PROGRAM_NAME)
269 throw failed_constructor ();
271 LXVSTPluginUI* lxvpu = new LXVSTPluginUI (insert, lxvp);
274 _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
276 lxvpu->package (*this);
284 #ifdef MACVST_SUPPORT
285 PluginUIWindow::create_mac_vst_editor (boost::shared_ptr<PluginInsert> insert)
287 PluginUIWindow::create_mac_vst_editor (boost::shared_ptr<PluginInsert>)
290 #ifndef MACVST_SUPPORT
293 boost::shared_ptr<MacVSTPlugin> mvst;
294 if ((mvst = boost::dynamic_pointer_cast<MacVSTPlugin> (insert->plugin())) == 0) {
295 error << string_compose (_("unknown type of editor-supplying plugin (note: no MacVST support in this version of %1)"), PROGRAM_NAME)
297 throw failed_constructor ();
299 VSTPluginUI* vpu = create_mac_vst_gui (insert);
301 _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
303 vpu->package (*this);
305 Application::instance()->ActivationChanged.connect (mem_fun (*this, &PluginUIWindow::app_activated));
313 #ifdef AUDIOUNIT_SUPPORT
314 PluginUIWindow::create_audiounit_editor (boost::shared_ptr<PluginInsert> insert)
316 PluginUIWindow::create_audiounit_editor (boost::shared_ptr<PluginInsert>)
319 #ifndef AUDIOUNIT_SUPPORT
323 _pluginui = create_au_gui (insert, &box);
324 _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
327 Application::instance()->ActivationChanged.connect (mem_fun (*this, &PluginUIWindow::app_activated));
335 PluginUIWindow::app_activated (bool yn)
337 PluginUIWindow::app_activated (bool)
340 #ifdef AUDIOUNIT_SUPPORT
344 _pluginui->activate ();
345 if (pre_deactivate_x >= 0) {
346 move (pre_deactivate_x, pre_deactivate_y);
352 was_visible = is_visible();
353 get_position (pre_deactivate_x, pre_deactivate_y);
355 _pluginui->deactivate ();
362 PluginUIWindow::create_lv2_editor(boost::shared_ptr<PluginInsert> insert)
365 boost::shared_ptr<LV2Plugin> vp;
367 if ((vp = boost::dynamic_pointer_cast<LV2Plugin> (insert->plugin())) == 0) {
368 error << _("create_lv2_editor called on non-LV2 plugin") << endmsg;
369 throw failed_constructor ();
371 LV2PluginUI* lpu = new LV2PluginUI (insert, vp);
374 lpu->package (*this);
375 _pluginui->KeyboardFocused.connect (sigc::mem_fun (*this, &PluginUIWindow::keyboard_focused));
385 PluginUIWindow::keyboard_focused (bool yn)
387 _keyboard_focused = yn;
391 PluginUIWindow::on_key_press_event (GdkEventKey* event)
393 if (_keyboard_focused) {
395 _pluginui->grab_focus();
396 if (_pluginui->non_gtk_gui()) {
397 _pluginui->forward_key_event (event);
399 return relay_key_press (event, this);
404 /* for us to be getting key press events, there really
405 MUST be a _pluginui, but just to be safe, check ...
409 _pluginui->grab_focus();
410 if (_pluginui->non_gtk_gui()) {
411 /* pass main window as the window for the event
412 to be handled in, not this one, because there are
413 no widgets in this window that we want to have
416 return relay_key_press (event, &ARDOUR_UI::instance()->main_window());
418 return relay_key_press (event, this);
426 PluginUIWindow::on_key_release_event (GdkEventKey *event)
428 if (_keyboard_focused) {
430 if (_pluginui->non_gtk_gui()) {
431 _pluginui->forward_key_event (event);
435 gtk_window_propagate_key_event (GTK_WINDOW(gobj()), event);
437 /* don't forward releases */
442 PluginUIWindow::plugin_going_away ()
444 ENSURE_GUI_THREAD (*this, &PluginUIWindow::plugin_going_away)
447 _pluginui->stop_updating(0);
450 death_connection.disconnect ();
453 PlugUIBase::PlugUIBase (boost::shared_ptr<PluginInsert> pi)
455 , plugin (insert->plugin())
456 , add_button (_("Add"))
457 , save_button (_("Save"))
458 , delete_button (_("Delete"))
459 , reset_button (_("Reset"))
460 , bypass_button (ArdourButton::led_default_elements)
461 , pin_management_button (_("Pinout"))
462 , description_expander (_("Description"))
463 , plugin_analysis_expander (_("Plugin analysis"))
464 , cpuload_expander (_("CPU Profile"))
469 _preset_modified.set_size_request (16, -1);
470 _preset_combo.set_text("(default)");
471 set_tooltip (_preset_combo, _("Presets (if any) for this plugin\n(Both factory and user-created)"));
472 set_tooltip (add_button, _("Save a new preset"));
473 set_tooltip (save_button, _("Save the current preset"));
474 set_tooltip (delete_button, _("Delete the current preset"));
475 set_tooltip (reset_button, _("Reset parameters to default (if no parameters are in automation play mode)"));
476 set_tooltip (pin_management_button, _("Show Plugin Pin Management Dialog"));
477 set_tooltip (bypass_button, _("Disable signal processing by the plugin"));
480 update_preset_list ();
483 add_button.set_name ("generic button");
484 add_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::add_plugin_setting));
486 save_button.set_name ("generic button");
487 save_button.signal_clicked.connect(sigc::mem_fun(*this, &PlugUIBase::save_plugin_setting));
489 delete_button.set_name ("generic button");
490 delete_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::delete_plugin_setting));
492 reset_button.set_name ("generic button");
493 reset_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::reset_plugin_parameters));
495 pin_management_button.set_name ("generic button");
496 pin_management_button.signal_clicked.connect (sigc::mem_fun (*this, &PlugUIBase::manage_pins));
498 insert->ActiveChanged.connect (active_connection, invalidator (*this), boost::bind (&PlugUIBase::processor_active_changed, this, boost::weak_ptr<Processor>(insert)), gui_context());
500 bypass_button.set_name ("plugin bypass button");
501 bypass_button.set_text (_("Bypass"));
502 bypass_button.set_active (!pi->enabled ());
503 bypass_button.signal_button_release_event().connect (sigc::mem_fun(*this, &PlugUIBase::bypass_button_release), false);
504 focus_button.add_events (Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
506 focus_button.signal_button_release_event().connect (sigc::mem_fun(*this, &PlugUIBase::focus_toggled));
507 focus_button.add_events (Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
509 /* these images are not managed, so that we can remove them at will */
511 focus_out_image = new Image (get_icon (X_("computer_keyboard")));
512 focus_in_image = new Image (get_icon (X_("computer_keyboard_active")));
514 focus_button.add (*focus_out_image);
516 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));
517 set_tooltip (bypass_button, _("Click to enable/disable this plugin"));
519 description_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &PlugUIBase::toggle_description));
520 description_expander.set_expanded(false);
522 plugin_analysis_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &PlugUIBase::toggle_plugin_analysis));
523 plugin_analysis_expander.set_expanded(false);
525 cpuload_expander.property_expanded().signal_changed().connect( sigc::mem_fun(*this, &PlugUIBase::toggle_cpuload_display));
526 cpuload_expander.set_expanded(false);
528 insert->DropReferences.connect (death_connection, invalidator (*this), boost::bind (&PlugUIBase::plugin_going_away, this), gui_context());
530 plugin->PresetAdded.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::preset_added_or_removed, this), gui_context ());
531 plugin->PresetRemoved.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::preset_added_or_removed, this), gui_context ());
532 plugin->PresetLoaded.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::update_preset, this), gui_context ());
533 plugin->PresetDirty.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::update_preset_modified, this), gui_context ());
535 insert->AutomationStateChanged.connect (*this, invalidator (*this), boost::bind (&PlugUIBase::automation_state_changed, this), gui_context());
537 automation_state_changed();
540 PlugUIBase::~PlugUIBase()
547 PlugUIBase::plugin_going_away ()
549 /* drop references to the plugin/insert */
555 PlugUIBase::set_latency_label ()
557 samplecnt_t const l = insert->effective_latency ();
558 samplecnt_t const sr = insert->session().sample_rate ();
563 t = string_compose (P_("latency (%1 sample)", "latency (%1 samples)", l), l);
565 t = string_compose (_("latency (%1 ms)"), (float) l / ((float) sr / 1000.0f));
568 latency_button.set_text (t);
572 PlugUIBase::latency_button_clicked ()
575 latency_gui = new LatencyGUI (*(insert.get()), insert->session().sample_rate(), insert->session().get_block_size());
576 latency_dialog = new ArdourWindow (_("Edit Latency"));
577 /* use both keep-above and transient for to try cover as many
578 different WM's as possible.
580 latency_dialog->set_keep_above (true);
581 Window* win = dynamic_cast<Window*> (bypass_button.get_toplevel ());
583 latency_dialog->set_transient_for (*win);
585 latency_dialog->add (*latency_gui);
586 latency_dialog->signal_hide().connect (sigc::mem_fun (*this, &PlugUIBase::set_latency_label));
589 latency_dialog->show_all ();
593 PlugUIBase::processor_active_changed (boost::weak_ptr<Processor> weak_p)
595 ENSURE_GUI_THREAD (*this, &PlugUIBase::processor_active_changed, weak_p);
596 boost::shared_ptr<Processor> p (weak_p.lock());
599 bypass_button.set_active (!p->enabled ());
604 PlugUIBase::preset_selected (Plugin::PresetRecord preset)
606 if (_no_load_preset) {
609 if (!preset.label.empty()) {
610 insert->load_preset (preset);
612 // blank selected = no preset
613 plugin->clear_preset();
617 #ifdef NO_PLUGIN_STATE
618 static bool seen_saving_message = false;
620 static void show_no_plugin_message()
622 info << string_compose (_("Plugin presets are not supported in this build of %1. Consider paying for a full version"),
625 info << _("To get full access to updates without this limitation\n"
626 "consider becoming a subscriber for a low cost every month.")
628 info << X_("https://community.ardour.org/s/subscribe")
630 ARDOUR_UI::instance()->popup_error(_("Plugin presets are not supported in this build, see the Log window for more information."));
635 PlugUIBase::add_plugin_setting ()
637 #ifndef NO_PLUGIN_STATE
638 NewPluginPresetDialog d (plugin, _("New Preset"));
641 case Gtk::RESPONSE_ACCEPT:
642 if (d.name().empty()) {
647 plugin->remove_preset (d.name ());
650 Plugin::PresetRecord const r = plugin->save_preset (d.name());
651 if (!r.uri.empty ()) {
652 plugin->load_preset (r);
657 if (!seen_saving_message) {
658 seen_saving_message = true;
659 show_no_plugin_message();
665 PlugUIBase::save_plugin_setting ()
667 #ifndef NO_PLUGIN_STATE
668 string const name = _preset_combo.get_text ();
669 plugin->remove_preset (name);
670 Plugin::PresetRecord const r = plugin->save_preset (name);
671 if (!r.uri.empty ()) {
672 plugin->load_preset (r);
675 if (!seen_saving_message) {
676 seen_saving_message = true;
677 show_no_plugin_message();
683 PlugUIBase::delete_plugin_setting ()
685 #ifndef NO_PLUGIN_STATE
686 plugin->remove_preset (_preset_combo.get_text ());
688 if (!seen_saving_message) {
689 seen_saving_message = true;
690 show_no_plugin_message();
696 PlugUIBase::automation_state_changed ()
698 reset_button.set_sensitive (insert->can_reset_all_parameters());
702 PlugUIBase::reset_plugin_parameters ()
704 insert->reset_parameters_to_default ();
708 PlugUIBase::manage_pins ()
710 PluginPinWindowProxy* proxy = insert->pinmgr_proxy ();
714 proxy->get ()->raise();
719 PlugUIBase::bypass_button_release (GdkEventButton*)
721 bool view_says_bypassed = (bypass_button.active_state() != 0);
723 if (view_says_bypassed != insert->enabled ()) {
724 insert->enable (view_says_bypassed);
731 PlugUIBase::focus_toggled (GdkEventButton*)
733 if (Keyboard::the_keyboard().some_magic_widget_has_focus()) {
734 Keyboard::the_keyboard().magic_widget_drop_focus();
735 focus_button.remove ();
736 focus_button.add (*focus_out_image);
737 focus_out_image->show ();
738 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));
739 KeyboardFocused (false);
741 Keyboard::the_keyboard().magic_widget_grab_focus();
742 focus_button.remove ();
743 focus_button.add (*focus_in_image);
744 focus_in_image->show ();
745 set_tooltip (focus_button, string_compose (_("Click to allow normal use of %1 keyboard shortcuts"), PROGRAM_NAME));
746 KeyboardFocused (true);
753 PlugUIBase::toggle_description()
755 if (description_expander.get_expanded() &&
756 !description_expander.get_child()) {
757 const std::string text = plugin->get_docs();
762 Gtk::Label* label = manage(new Gtk::Label(text));
763 label->set_line_wrap(true);
764 label->set_line_wrap_mode(Pango::WRAP_WORD);
765 description_expander.add(*label);
766 description_expander.show_all();
769 if (!description_expander.get_expanded()) {
770 const int child_height = description_expander.get_child ()->get_height ();
772 description_expander.remove();
774 Gtk::Window *toplevel = (Gtk::Window*) description_expander.get_ancestor (GTK_TYPE_WINDOW);
778 toplevel->get_size (wr.width, wr.height);
779 wr.height -= child_height;
780 toplevel->resize (wr.width, wr.height);
788 PlugUIBase::toggle_plugin_analysis()
790 if (plugin_analysis_expander.get_expanded() &&
791 !plugin_analysis_expander.get_child()) {
794 eqgui = new PluginEqGui (insert);
797 plugin_analysis_expander.add (*eqgui);
798 plugin_analysis_expander.show_all ();
799 eqgui->start_listening ();
802 if (!plugin_analysis_expander.get_expanded()) {
803 // Hide & remove from expander
804 const int child_height = plugin_analysis_expander.get_child ()->get_height ();
807 eqgui->stop_listening ();
808 plugin_analysis_expander.remove();
810 Gtk::Window *toplevel = (Gtk::Window*) plugin_analysis_expander.get_ancestor (GTK_TYPE_WINDOW);
814 toplevel->get_size (wr.width, wr.height);
815 wr.height -= child_height;
816 toplevel->resize (wr.width, wr.height);
822 PlugUIBase::update_cpu_label()
827 if (insert->get_stats (min, max, avg, dev)) {
828 t = string_compose (_("Timing min: %1 [ms] max: %2 [ms]\navg: %3 [ms] std.dev: %4"),
829 rint (min / 100.) / 10.,
830 rint (max / 100.) / 10.,
834 t = _("No data available");
836 cpuload_label.set_text (t);
840 PlugUIBase::toggle_cpuload_display()
842 if (cpuload_expander.get_expanded() && !cpuload_expander.get_child()) {
844 cpuload_label.set_line_wrap(true);
845 cpuload_label.set_line_wrap_mode(Pango::WRAP_WORD);
846 update_cpu_label_connection = Timers::second_connect (sigc::mem_fun(*this, &PlugUIBase::update_cpu_label));
848 cpuload_expander.add(cpuload_label);
849 cpuload_expander.show_all();
852 if (!cpuload_expander.get_expanded()) {
853 update_cpu_label_connection.disconnect ();
854 const int child_height = cpuload_expander.get_child ()->get_height ();
855 cpuload_expander.remove();
856 Gtk::Window *toplevel = (Gtk::Window*) cpuload_expander.get_ancestor (GTK_TYPE_WINDOW);
860 toplevel->get_size (wr.width, wr.height);
861 wr.height -= child_height;
862 toplevel->resize (wr.width, wr.height);
869 PlugUIBase::update_preset_list ()
871 using namespace Menu_Helpers;
873 vector<ARDOUR::Plugin::PresetRecord> presets = plugin->get_presets();
877 // Add a menu entry for each preset
878 _preset_combo.clear_items();
879 for (vector<ARDOUR::Plugin::PresetRecord>::const_iterator i = presets.begin(); i != presets.end(); ++i) {
880 _preset_combo.AddMenuElem(
881 MenuElem(i->label, sigc::bind(sigc::mem_fun(*this, &PlugUIBase::preset_selected), *i)));
884 // Add an empty entry for un-setting current preset (see preset_selected)
885 Plugin::PresetRecord no_preset;
886 _preset_combo.AddMenuElem(
887 MenuElem("", sigc::bind(sigc::mem_fun(*this, &PlugUIBase::preset_selected), no_preset)));
893 PlugUIBase::update_preset ()
895 Plugin::PresetRecord p = plugin->last_preset();
899 _preset_combo.set_text (_("(none)"));
901 _preset_combo.set_text (p.label);
905 save_button.set_sensitive (!p.uri.empty() && p.user);
906 delete_button.set_sensitive (!p.uri.empty() && p.user);
908 update_preset_modified ();
912 PlugUIBase::update_preset_modified ()
915 if (plugin->last_preset().uri.empty()) {
916 _preset_modified.set_text ("");
920 bool const c = plugin->parameter_changed_since_last_preset ();
921 if (_preset_modified.get_text().empty() == c) {
922 _preset_modified.set_text (c ? "*" : "");
927 PlugUIBase::preset_added_or_removed ()
929 /* Update both the list and the currently-displayed preset */
930 update_preset_list ();