X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fplugin_selector.cc;h=3f03a218e523237612f3e779d202a36d71db6728;hb=bf874562ef14368a5648215b6dc71936f1c3b33e;hp=69f6f56690d696d1a365c452bf62ca4fce9ddd6b;hpb=82232f06ba3eea4a2b4342ad91fab552f4044402;p=ardour.git diff --git a/gtk2_ardour/plugin_selector.cc b/gtk2_ardour/plugin_selector.cc index 69f6f56690..3f03a218e5 100644 --- a/gtk2_ardour/plugin_selector.cc +++ b/gtk2_ardour/plugin_selector.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2006 Paul Davis + Copyright (C) 2000-2006 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,495 +16,1209 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifdef WAF_BUILD +#include "gtk2ardour-config.h" +#endif #include -#include +#include + +#include -#include -#include #include +#include +#include +#include #include +#include +#include +#include -#include -#include -#include +#include "gtkmm2ext/utils.h" + +#include "widgets/tooltips.h" + +#include "pbd/convert.h" +#include "pbd/tokenizer.h" + +#include "ardour/utils.h" -#include "ardour_ui.h" #include "plugin_selector.h" #include "gui_thread.h" +#include "ui_config.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace ARDOUR; using namespace PBD; using namespace Gtk; +using namespace std; +using namespace ArdourWidgets; -PluginSelector::PluginSelector (PluginManager *mgr) - : ArdourDialog (_("ardour: plugins"), true, false) +static const uint32_t MAX_CREATOR_LEN = 24; + +PluginSelector::PluginSelector (PluginManager& mgr) + : ArdourDialog (_("Plugin Manager"), true, false) + , search_clear_button (Stock::CLEAR) + , manager (mgr) + , _inhibit_refill (false) { - set_position (Gtk::WIN_POS_MOUSE); set_name ("PluginSelectorWindow"); add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK); - manager = mgr; - session = 0; - - current_selection = ARDOUR::LADSPA; - - lmodel = Gtk::ListStore::create(lcols); - ladspa_display.set_model (lmodel); - ladspa_display.append_column (_("Available LADSPA Plugins"), lcols.name); - ladspa_display.append_column (_("Type"), lcols.type); - ladspa_display.append_column (_("# Inputs"),lcols.ins); - ladspa_display.append_column (_("# Outputs"), lcols.outs); - ladspa_display.set_headers_visible (true); - ladspa_display.set_reorderable (false); - lscroller.set_border_width(10); - lscroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); - lscroller.add(ladspa_display); + _plugin_menu = 0; + in_row_change = false; + + //anytime the list changes ( Status, Tags, or scanned plugins ) we need to rebuild redirect-box plugin selector menu + manager.PluginListChanged.connect (plugin_list_changed_connection, invalidator (*this), boost::bind (&PluginSelector::build_plugin_menu, this), gui_context()); + + //these are used to update the info of specific entries, while they are being edited + manager.PluginStatusChanged.connect (plugin_list_changed_connection, invalidator (*this), boost::bind (&PluginSelector::plugin_status_changed, this, _1, _2, _3), gui_context()); + manager.PluginTagChanged.connect(plugin_list_changed_connection, invalidator (*this), boost::bind (&PluginSelector::tags_changed, this, _1, _2, _3), gui_context()); + + plugin_model = Gtk::ListStore::create (plugin_columns); + plugin_display.set_model (plugin_model); + /* XXX translators: try to convert "Fav" into a short term + * related to "favorite" and "Hid" into a short term + * related to "hidden" + */ + plugin_display.append_column (_("Fav"), plugin_columns.favorite); + plugin_display.append_column (_("Hide"), plugin_columns.hidden); + plugin_display.append_column (_("Name"), plugin_columns.name); + plugin_display.append_column (_("Tags"), plugin_columns.tags); + plugin_display.append_column (_("Creator"), plugin_columns.creator); + plugin_display.append_column (_("Type"), plugin_columns.type_name); + plugin_display.append_column (_("Audio I/O"),plugin_columns.audio_io); + plugin_display.append_column (_("MIDI I/O"), plugin_columns.midi_io); + plugin_display.set_headers_visible (true); + plugin_display.set_headers_clickable (true); + plugin_display.set_reorderable (false); + plugin_display.set_rules_hint (true); + plugin_display.add_object_drag (plugin_columns.plugin.index(), "PluginInfoPtr"); + plugin_display.set_drag_column (plugin_columns.name.index()); + + // setting a sort-column prevents re-ordering via Drag/Drop + plugin_model->set_sort_column (plugin_columns.name.index(), Gtk::SORT_ASCENDING); + + plugin_display.set_name("PluginSelectorDisplay"); + plugin_display.signal_row_activated().connect_notify (sigc::mem_fun(*this, &PluginSelector::row_activated)); + plugin_display.get_selection()->signal_changed().connect (sigc::mem_fun(*this, &PluginSelector::display_selection_changed)); + + CellRendererToggle* fav_cell = dynamic_cast(plugin_display.get_column_cell_renderer (0)); + fav_cell->property_activatable() = true; + fav_cell->property_radio() = true; + fav_cell->signal_toggled().connect (sigc::mem_fun (*this, &PluginSelector::favorite_changed)); + + CellRendererToggle* hidden_cell = dynamic_cast(plugin_display.get_column_cell_renderer (1)); + hidden_cell->property_activatable() = true; + hidden_cell->property_radio() = true; + hidden_cell->signal_toggled().connect (sigc::mem_fun (*this, &PluginSelector::hidden_changed)); + + scroller.set_border_width(10); + scroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + scroller.add(plugin_display); amodel = Gtk::ListStore::create(acols); added_list.set_model (amodel); - added_list.append_column (_("Plugins to be Connected to Insert"), acols.text); + added_list.append_column (_("Plugins to be connected"), acols.text); added_list.set_headers_visible (true); added_list.set_reorderable (false); - for (int i = 0; i <=3; i++) { - Gtk::TreeView::Column* column = ladspa_display.get_column(i); - column->set_sort_column(i); - } - -#ifdef VST_SUPPORT - vmodel = ListStore::create(vcols); - vst_display.set_model (vmodel); - vst_display.append_column (_("Available plugins"), vcols.name); - vst_display.append_column (_("# Inputs"), vcols.ins); - vst_display.append_column (_("# Outputs"), vcols.outs); - vst_display.set_headers_visible (true); - vst_display.set_reorderable (false); - vscroller.set_border_width(10); - vscroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); - vscroller.add(vst_display); - - for (int i = 0; i <=2; i++) { - Gtk::TreeView::Column* column = vst_display.get_column(i); - column->set_sort_column(i); + for (int i = 2; i <= 7; ++i) { + Gtk::TreeView::Column* column = plugin_display.get_column(i); + if (column) { + column->set_sort_column(i); + } } -#endif - -#ifdef HAVE_COREAUDIO - aumodel = ListStore::create(aucols); - au_display.set_model (aumodel); - au_display.append_column (_("Available plugins"), aucols.name); - au_display.append_column (_("# Inputs"), aucols.ins); - au_display.append_column (_("# Outputs"), aucols.outs); - au_display.set_headers_visible (true); - au_display.set_reorderable (false); - auscroller.set_border_width(10); - auscroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); - auscroller.add(au_display); - - for (int i = 0; i <=2; i++) { - Gtk::TreeView::Column* column = au_display.get_column(i); - column->set_sort_column(i); - } -#endif ascroller.set_border_width(10); ascroller.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); ascroller.add(added_list); btn_add = manage(new Gtk::Button(Stock::ADD)); - ARDOUR_UI::instance()->tooltips().set_tip(*btn_add, _("Add a plugin to the effect list")); + set_tooltip(*btn_add, _("Add a plugin to the effect list")); btn_add->set_sensitive (false); btn_remove = manage(new Gtk::Button(Stock::REMOVE)); btn_remove->set_sensitive (false); - ARDOUR_UI::instance()->tooltips().set_tip(*btn_remove, _("Remove a plugin from the effect list")); - Gtk::Button *btn_update = manage(new Gtk::Button(Stock::REFRESH)); - ARDOUR_UI::instance()->tooltips().set_tip(*btn_update, _("Update available plugins")); + set_tooltip(*btn_remove, _("Remove a plugin from the effect list")); btn_add->set_name("PluginSelectorButton"); btn_remove->set_name("PluginSelectorButton"); - Gtk::Table* table = manage(new Gtk::Table(7, 10)); - table->set_size_request(750, 500); - table->attach(notebook, 0, 7, 0, 5); + /* SEARCH */ + + Gtk::Table* search_table = manage(new Gtk::Table(2, 2)); + + search_entry.signal_changed().connect (sigc::mem_fun (*this, &PluginSelector::search_entry_changed)); + search_clear_button.signal_clicked().connect (sigc::mem_fun (*this, &PluginSelector::search_clear_button_clicked)); + + _search_name_checkbox = manage (new ArdourButton (_("Name"), ArdourButton::led_default_elements, true)); + _search_name_checkbox->set_active(true); + _search_name_checkbox->set_name ("pluginlist filter button"); + + _search_tags_checkbox = manage (new ArdourButton (_("Tags"), ArdourButton::led_default_elements, true)); + _search_tags_checkbox->set_active(true); + _search_tags_checkbox->set_name ("pluginlist filter button"); - table->attach(*btn_add, 1, 2, 5, 6, Gtk::FILL, Gtk::FILL, 5, 5); - table->attach(*btn_remove, 3, 4, 5, 6, Gtk::FILL, Gtk::FILL, 5, 5); - table->attach(*btn_update, 5, 6, 5, 6, Gtk::FILL, Gtk::FILL, 5, 5); + _search_ignore_checkbox = manage (new ArdourButton(_("Ignore Filters when searching"), ArdourButton::led_default_elements, true)); + _search_ignore_checkbox->set_active(true); + _search_ignore_checkbox->set_name ("pluginlist filter button"); - table->attach(ascroller, 0, 7, 7, 9); + Gtk::Label* search_help_label1 = manage (new Label( + _("All search terms must be matched."), Gtk::ALIGN_LEFT)); - add_button (Stock::CANCEL, RESPONSE_CANCEL); - add_button (Stock::CONNECT, RESPONSE_APPLY); + Gtk::Label* search_help_label2 = manage (new Label( + _("Ex: \"ess dyn\" will find \"dynamic de-esser\" but not \"de-esser\"."), Gtk::ALIGN_LEFT)); + + search_table->attach (search_entry, 0, 3, 0, 1, FILL|EXPAND, FILL); + search_table->attach (search_clear_button, 3, 4, 0, 1, FILL, FILL); + search_table->attach (*_search_name_checkbox, 0, 1, 1, 2, FILL, FILL); + search_table->attach (*_search_tags_checkbox, 1, 2, 1, 2, FILL, FILL); + search_table->attach (*_search_ignore_checkbox,2, 3, 1, 2, FILL, FILL); + search_table->attach (*search_help_label1, 0, 3, 2, 3, FILL, FILL); + search_table->attach (*search_help_label2, 0, 3, 3, 4, FILL, FILL); + + search_table->set_border_width (4); + search_table->set_col_spacings (4); + search_table->set_row_spacings (4); + + Frame* search_frame = manage (new Frame); + search_frame->set_name ("BaseFrame"); + search_frame->set_label (_("Search")); + search_frame->add (*search_table); + search_frame->show_all (); + + _search_name_checkbox->signal_clicked.connect (sigc::mem_fun (*this, &PluginSelector::refill)); + _search_tags_checkbox->signal_clicked.connect (sigc::mem_fun (*this, &PluginSelector::refill)); + _search_ignore_checkbox->signal_clicked.connect (sigc::mem_fun (*this, &PluginSelector::set_sensitive_widgets)); + + /* FILTER */ + + Gtk::RadioButtonGroup fil_radio_group; + + _fil_effects_radio = manage (new RadioButton (fil_radio_group, _("Show Effects Only"))); + _fil_instruments_radio = manage (new RadioButton (fil_radio_group, _("Show Instruments Only"))); + _fil_utils_radio = manage (new RadioButton (fil_radio_group, _("Show Utilities Only"))); + _fil_favorites_radio = manage (new RadioButton (fil_radio_group, _("Show Favorites Only"))); + _fil_hidden_radio = manage (new RadioButton (fil_radio_group, _("Show Hidden Only"))); + _fil_all_radio = manage (new RadioButton (fil_radio_group, _("Show All"))); + + //_fil_type_combo = manage (new ComboBoxText); + _fil_type_combo.append_text_item (_("Show All Formats")); + _fil_type_combo.append_text_item (X_("VST")); +#ifdef AUDIOUNIT_SUPPORT + _fil_type_combo.append_text_item (X_("AudioUnit")); +#endif +#ifdef LV2_SUPPORT + _fil_type_combo.append_text_item (X_("LV2")); +#endif + _fil_type_combo.append_text_item (X_("Lua")); + _fil_type_combo.append_text_item (X_("LADSPA")); + _fil_type_combo.set_text (_("Show All Formats")); + + /* note: _fil_creator_combo menu gets filled in build_plugin_menu */ + _fil_creator_combo.set_text_ellipsize (Pango::ELLIPSIZE_END); + _fil_creator_combo.set_layout_ellipsize_width (PANGO_SCALE * 160 * UIConfiguration::instance ().get_ui_scale ()); + + VBox* filter_vbox = manage (new VBox); + filter_vbox->pack_start (*_fil_effects_radio, false, false); + filter_vbox->pack_start (*_fil_instruments_radio, false, false); + filter_vbox->pack_start (*_fil_utils_radio, false, false); + filter_vbox->pack_start (*_fil_favorites_radio, false, false); + filter_vbox->pack_start (*_fil_hidden_radio, false, false); + filter_vbox->pack_start (*_fil_all_radio, false, false); + filter_vbox->pack_start (_fil_type_combo, false, false); + filter_vbox->pack_start (_fil_creator_combo, false, false); + + filter_vbox->set_border_width (4); + filter_vbox->set_spacing (4); + + Frame* filter_frame = manage (new Frame); + filter_frame->set_name ("BaseFrame"); + filter_frame->set_label (_("Filter")); + filter_frame->add (*filter_vbox); + filter_frame->show_all (); + + _fil_effects_radio->signal_clicked().connect (sigc::mem_fun (*this, &PluginSelector::refill)); + _fil_instruments_radio->signal_clicked().connect (sigc::mem_fun (*this, &PluginSelector::refill)); + _fil_utils_radio->signal_clicked().connect (sigc::mem_fun (*this, &PluginSelector::refill)); + _fil_favorites_radio->signal_clicked().connect (sigc::mem_fun (*this, &PluginSelector::refill)); + _fil_hidden_radio->signal_clicked().connect (sigc::mem_fun (*this, &PluginSelector::refill)); + + _fil_type_combo.StateChanged.connect (sigc::mem_fun (*this, &PluginSelector::refill)); + _fil_creator_combo.StateChanged.connect (sigc::mem_fun (*this, &PluginSelector::refill)); + + /* TAG entry */ + + Gtk::Table* tagging_table = manage(new Gtk::Table(1, 2)); + tagging_table->set_border_width (4); + tagging_table->set_col_spacings (4); + tagging_table->set_row_spacings (4); + + tag_entry = manage (new Gtk::Entry); + tag_entry_connection = tag_entry->signal_changed().connect (sigc::mem_fun (*this, &PluginSelector::tag_entry_changed)); + + tag_reset_button = manage (new Button (_("Reset"))); + tag_reset_button->signal_clicked().connect (sigc::mem_fun (*this, &PluginSelector::tag_reset_button_clicked)); + + Gtk::Label* tagging_help_label1 = manage (new Label( + _("Enter space-separated, one-word Tags for the selected plugin."), Gtk::ALIGN_LEFT)); + + Gtk::Label* tagging_help_label2 = manage (new Label( + _("You can include dashes, colons or underscores in a Tag."), Gtk::ALIGN_LEFT)); + + Gtk::Label* tagging_help_label3 = manage (new Label( + _("Ex: \"dynamic de-esser vocal\" applies 3 Tags."), Gtk::ALIGN_LEFT)); + + int p = 0; + tagging_table->attach (*tag_entry, 0, 1, p, p+1, FILL|EXPAND, FILL); + tagging_table->attach (*tag_reset_button, 1, 2, p, p+1, FILL, FILL); p++; + tagging_table->attach (*tagging_help_label1, 0, 2, p, p+1, FILL, FILL); p++; + tagging_table->attach (*tagging_help_label2, 0, 2, p, p+1, FILL, FILL); p++; + tagging_table->attach (*tagging_help_label3, 0, 2, p, p+1, FILL, FILL); p++; + + Frame* tag_frame = manage (new Frame); + tag_frame->set_name ("BaseFrame"); + tag_frame->set_label (_("Tags for Selected Plugin")); + tag_frame->add (*tagging_table); + tag_frame->show_all (); + + /* Add & remove buttons */ + + HBox* add_remove = manage (new HBox); + add_remove->pack_start (*btn_add, true, true); + add_remove->pack_start (*btn_remove, true, true); + + btn_add->signal_clicked().connect(sigc::mem_fun(*this, &PluginSelector::btn_add_clicked)); + btn_remove->signal_clicked().connect(sigc::mem_fun(*this, &PluginSelector::btn_remove_clicked)); + added_list.get_selection()->signal_changed().connect (sigc::mem_fun(*this, &PluginSelector::added_list_selection_changed)); + added_list.signal_button_press_event().connect_notify (mem_fun(*this, &PluginSelector::added_row_clicked)); + + added_list.set_name("PluginSelectorList"); + + /* Top-level Layout */ + + VBox* to_be_inserted_vbox = manage (new VBox); + to_be_inserted_vbox->pack_start (ascroller); + to_be_inserted_vbox->pack_start (*add_remove, false, false); + to_be_inserted_vbox->set_size_request (200, -1); + + Gtk::Table* table = manage(new Gtk::Table(3, 3)); + table->set_size_request(-1, 600); + table->attach (scroller, 0, 3, 0, 5); /* this is the main plugin list */ + table->attach (*search_frame, 0, 1, 6, 7, FILL, FILL, 5, 5); + table->attach (*tag_frame, 0, 1, 7, 8, FILL, FILL, 5, 5); + table->attach (*filter_frame, 1, 2, 6, 8, FILL, FILL, 5, 5); + table->attach (*to_be_inserted_vbox, 2, 3, 6, 8, FILL|EXPAND, FILL, 5, 5); /* to be inserted... */ + + add_button (Stock::CLOSE, RESPONSE_CLOSE); + add_button (_("Insert Plugin(s)"), RESPONSE_APPLY); set_default_response (RESPONSE_APPLY); set_response_sensitive (RESPONSE_APPLY, false); get_vbox()->pack_start (*table); - // Notebook tab order must be the same in here as in set_correct_focus() - using namespace Gtk::Notebook_Helpers; - notebook.pages().push_back (TabElem (lscroller, _("LADSPA"))); + table->set_name("PluginSelectorTable"); + + plugin_display.grab_focus(); + + build_plugin_menu (); + display_selection_changed (); +} + +PluginSelector::~PluginSelector () +{ + delete _plugin_menu; +} + +void +PluginSelector::row_activated(Gtk::TreeModel::Path, Gtk::TreeViewColumn*) +{ + btn_add_clicked(); +} + +void +PluginSelector::added_row_clicked(GdkEventButton* event) +{ + if (event->type == GDK_2BUTTON_PRESS) + btn_remove_clicked(); +} -#ifdef VST_SUPPORT - if (Config->get_use_vst()) { - notebook.pages().push_back (TabElem (vscroller, _("VST"))); +bool +PluginSelector::show_this_plugin (const PluginInfoPtr& info, const std::string& searchstr) +{ + string mode; + bool maybe_show = false; + + if (!searchstr.empty()) { + + std::string compstr; + + if (_search_name_checkbox->get_active()) { /* name contains */ + compstr = info->name; + transform (compstr.begin(), compstr.end(), compstr.begin(), ::toupper); + if (compstr.find (searchstr) != string::npos) { + maybe_show = true; + } + } + + if (_search_tags_checkbox->get_active()) { /* tag contains */ + compstr = manager.get_tags_as_string (info); + transform (compstr.begin(), compstr.end(), compstr.begin(), ::toupper); + if (compstr.find (searchstr) != string::npos) { + maybe_show = true; + } + } + + if (!maybe_show) { + return false; + } + + /* user asked to ignore filters */ + if (maybe_show && _search_ignore_checkbox->get_active()) { + if (manager.get_status (info) == PluginManager::Hidden) { + return false; + } + return true; + } } -#endif -#ifdef HAVE_COREAUDIO - notebook.pages().push_back (TabElem (auscroller, _("AudioUnit"))); -#endif + if (_fil_effects_radio->get_active() && !info->is_effect()) { + return false; + } - table->set_name("PluginSelectorTable"); - ladspa_display.set_name("PluginSelectorDisplay"); - //ladspa_display.set_name("PluginSelectorList"); - added_list.set_name("PluginSelectorList"); + if (_fil_instruments_radio->get_active() && !info->is_instrument()) { + return false; + } - ladspa_display.signal_button_press_event().connect_notify (mem_fun(*this, &PluginSelector::row_clicked)); - ladspa_display.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::ladspa_display_selection_changed)); - ladspa_display.grab_focus(); - -#ifdef VST_SUPPORT - if (Config->get_use_vst()) { - vst_display.signal_button_press_event().connect_notify (mem_fun(*this, &PluginSelector::row_clicked)); - vst_display.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::vst_display_selection_changed)); + if (_fil_utils_radio->get_active() && !(info->is_utility() || info->is_analyzer())) { + return false; } -#endif -#ifdef HAVE_COREAUDIO - au_display.signal_button_press_event().connect_notify (mem_fun(*this, &PluginSelector::row_clicked)); - au_display.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::au_display_selection_changed)); -#endif + if (_fil_favorites_radio->get_active() && !(manager.get_status (info) == PluginManager::Favorite)) { + return false; + } - btn_update->signal_clicked().connect (mem_fun(*this, &PluginSelector::btn_update_clicked)); - btn_add->signal_clicked().connect(mem_fun(*this, &PluginSelector::btn_add_clicked)); - btn_remove->signal_clicked().connect(mem_fun(*this, &PluginSelector::btn_remove_clicked)); - added_list.get_selection()->signal_changed().connect (mem_fun(*this, &PluginSelector::added_list_selection_changed)); + if (_fil_hidden_radio->get_active() && !(manager.get_status (info) == PluginManager::Hidden)) { + return false; + } - input_refiller (); - -#ifdef VST_SUPPORT - vst_refiller (); -#endif + if (!_fil_hidden_radio->get_active() && manager.get_status (info) == PluginManager::Hidden) { + return false; + } + + /* Filter "type" combobox */ + + if (_fil_type_combo.get_text() == X_("VST") && PluginManager::to_generic_vst(info->type) != LXVST) { + return false; + } + + if (_fil_type_combo.get_text() == X_("AudioUnit") && info->type != AudioUnit) { + return false; + } -#ifdef HAVE_COREAUDIO - au_refiller (); +#ifdef LV2_SUPPORT + if (_fil_type_combo.get_text() == X_("LV2") && info->type != LV2) { + return false; + } #endif - signal_show().connect (mem_fun (*this, &PluginSelector::set_correct_focus)); + if (_fil_type_combo.get_text() == X_("Lua") && info->type != Lua) { + return false; + } + + if (_fil_type_combo.get_text() == X_("LADSPA") && info->type != LADSPA) { + return false; + } + + /* Filter "creator" combobox */ + + if (_fil_creator_combo.get_text() != _("Show All Creators")) { + if (_fil_creator_combo.get_text() != info->creator) { + return false; + } + } + + return true; } -/** - * Makes sure keyboard focus is always in the plugin list - * of the selected notebook tab. - **/ void -PluginSelector::set_correct_focus() +PluginSelector::setup_search_string (string& searchstr) { - int cp = notebook.get_current_page(); + searchstr = search_entry.get_text (); + transform (searchstr.begin(), searchstr.end(), searchstr.begin(), ::toupper); +} - if (cp == 0) { - ladspa_display.grab_focus(); - return; +void +PluginSelector::set_sensitive_widgets () +{ + if (_search_ignore_checkbox->get_active() && !search_entry.get_text().empty()) { + _fil_effects_radio->set_sensitive(false); + _fil_instruments_radio->set_sensitive(false); + _fil_utils_radio->set_sensitive(false); + _fil_favorites_radio->set_sensitive(false); + _fil_hidden_radio->set_sensitive(false); + _fil_all_radio->set_sensitive(false); + _inhibit_refill = true; + _fil_type_combo.set_sensitive(false); + _fil_creator_combo.set_sensitive(false); + _inhibit_refill = false; + } else { + _fil_effects_radio->set_sensitive(true); + _fil_instruments_radio->set_sensitive(true); + _fil_utils_radio->set_sensitive(true); + _fil_favorites_radio->set_sensitive(true); + _fil_hidden_radio->set_sensitive(true); + _fil_all_radio->set_sensitive(true); + _inhibit_refill = true; + _fil_type_combo.set_sensitive(true); + _fil_creator_combo.set_sensitive(true); + _inhibit_refill = false; + } + if (!search_entry.get_text().empty()) { + refill (); } +} -#ifdef VST_SUPPORT - if (Config->get_use_vst()) { - cp--; - - if (cp == 0) { - vst_display.grab_focus(); - return; - } +void +PluginSelector::refill () +{ + if (_inhibit_refill) { + return; } -#endif -#ifdef HAVE_COREAUDIO - cp--; + std::string searchstr; - if (cp == 0) { - au_display.grab_focus(); - return; + in_row_change = true; + + plugin_display.set_model (Glib::RefPtr(0)); + + int sort_col; + SortType sort_type; + bool sorted = plugin_model->get_sort_column_id (sort_col, sort_type); + + /* Disable sorting to gain performance */ + plugin_model->set_sort_column (-2, SORT_ASCENDING); + + plugin_model->clear (); + + setup_search_string (searchstr); + + ladspa_refiller (searchstr); + lv2_refiller (searchstr); + vst_refiller (searchstr); + lxvst_refiller (searchstr); + mac_vst_refiller (searchstr); + au_refiller (searchstr); + lua_refiller (searchstr); + + in_row_change = false; + + plugin_display.set_model (plugin_model); + if (sorted) { + plugin_model->set_sort_column (sort_col, sort_type); } +} + +void +PluginSelector::refiller (const PluginInfoList& plugs, const::std::string& searchstr, const char* type) +{ + char buf[16]; + + for (PluginInfoList::const_iterator i = plugs.begin(); i != plugs.end(); ++i) { + + if (show_this_plugin (*i, searchstr)) { + + TreeModel::Row newrow = *(plugin_model->append()); + newrow[plugin_columns.favorite] = (manager.get_status (*i) == PluginManager::Favorite); + newrow[plugin_columns.hidden] = (manager.get_status (*i) == PluginManager::Hidden); + + string name = (*i)->name; + if (name.length() > 48) { + name = name.substr (0, 48); + name.append("..."); + } + newrow[plugin_columns.name] = name; + + newrow[plugin_columns.type_name] = type; + + /* Creator */ + string creator = (*i)->creator; + string::size_type pos = 0; + if ((*i)->type == ARDOUR::LADSPA) { + /* stupid LADSPA creator strings */ +#ifdef PLATFORM_WINDOWS + while (pos < creator.length() && creator[pos] > -2 && creator[pos] < 256 && (isalnum (creator[pos]) || isspace (creator[pos]))) ++pos; +#else + while (pos < creator.length() && (isalnum (creator[pos]) || isspace (creator[pos]))) ++pos; #endif + } else { + pos = creator.length (); + } + // If there were too few characters to create a + // meaningful name, mark this creator as 'Unknown' + if (creator.length() < 2 || pos < 3) { + creator = "Unknown"; + } else{ + creator = creator.substr (0, pos); + } + + if (creator.length() > MAX_CREATOR_LEN) { + creator = creator.substr (0, MAX_CREATOR_LEN); + creator.append("..."); + } + newrow[plugin_columns.creator] = creator; + + /* Tags */ + string tags = manager.get_tags_as_string(*i); + if (tags.length() > 32) { + tags = tags.substr (0, 32); + tags.append("..."); + } + newrow[plugin_columns.tags] = tags; + + if ((*i)->reconfigurable_io ()) { + newrow[plugin_columns.audio_io] = "* / *"; + newrow[plugin_columns.midi_io] = "* / *"; + } else { + snprintf (buf, sizeof(buf), "%d / %d", (*i)->n_inputs.n_audio(), (*i)->n_outputs.n_audio()); + newrow[plugin_columns.audio_io] = buf; + snprintf (buf, sizeof(buf), "%d / %d", (*i)->n_inputs.n_midi(), (*i)->n_outputs.n_midi()); + newrow[plugin_columns.midi_io] = buf; + } + + newrow[plugin_columns.plugin] = *i; + } + } } void -PluginSelector::row_clicked(GdkEventButton* event) +PluginSelector::ladspa_refiller (const std::string& searchstr) { - if (event->type == GDK_2BUTTON_PRESS) - btn_add_clicked(); + refiller (manager.ladspa_plugin_info(), searchstr, "LADSPA"); } void -PluginSelector::set_session (Session* s) +PluginSelector::lua_refiller (const std::string& searchstr) { - ENSURE_GUI_THREAD(bind (mem_fun(*this, &PluginSelector::set_session), s)); - - session = s; + refiller (manager.lua_plugin_info(), searchstr, "Lua"); +} - if (session) { - session->GoingAway.connect (bind (mem_fun(*this, &PluginSelector::set_session), static_cast (0))); - } +void +PluginSelector::lv2_refiller (const std::string& searchstr) +{ +#ifdef LV2_SUPPORT + refiller (manager.lv2_plugin_info(), searchstr, "LV2"); +#endif } void -PluginSelector::_input_refiller (void *arg) +#ifdef WINDOWS_VST_SUPPORT +PluginSelector::vst_refiller (const std::string& searchstr) +#else +PluginSelector::vst_refiller (const std::string&) +#endif { - ((PluginSelector *) arg)->input_refiller (); +#ifdef WINDOWS_VST_SUPPORT + refiller (manager.windows_vst_plugin_info(), searchstr, "VST"); +#endif } -int compare(const void *left, const void *right) +void +#ifdef LXVST_SUPPORT +PluginSelector::lxvst_refiller (const std::string& searchstr) +#else +PluginSelector::lxvst_refiller (const std::string&) +#endif { - return strcmp(*((char**)left), *((char**)right)); +#ifdef LXVST_SUPPORT + refiller (manager.lxvst_plugin_info(), searchstr, "LXVST"); +#endif } void -PluginSelector::input_refiller () +#ifdef MACVST_SUPPORT +PluginSelector::mac_vst_refiller (const std::string& searchstr) +#else +PluginSelector::mac_vst_refiller (const std::string&) +#endif { - guint row; - PluginInfoList &plugs = manager->ladspa_plugin_info (); - PluginInfoList::iterator i; - char ibuf[16], obuf[16]; - lmodel->clear(); +#ifdef MACVST_SUPPORT + refiller (manager.mac_vst_plugin_info(), searchstr, "MacVST"); +#endif +} - // Insert into GTK list - for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) { - snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs); - snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs); - - Gtk::TreeModel::Row newrow = *(lmodel->append()); - newrow[lcols.name] = (*i)->name.c_str(); - newrow[lcols.type] = (*i)->category.c_str(); - newrow[lcols.ins] = ibuf; - newrow[lcols.outs] = obuf; - newrow[lcols.plugin] = *i; +void +#ifdef AUDIOUNIT_SUPPORT +PluginSelector::au_refiller (const std::string& searchstr) +#else +PluginSelector::au_refiller (const std::string&) +#endif +{ +#ifdef AUDIOUNIT_SUPPORT + refiller (manager.au_plugin_info(), searchstr, "AU"); +#endif +} + +PluginPtr +PluginSelector::load_plugin (PluginInfoPtr pi) +{ + if (_session == 0) { + return PluginPtr(); } - lmodel->set_sort_column (0, Gtk::SORT_ASCENDING); + return pi->load (*_session); } -#ifdef VST_SUPPORT - void -PluginSelector::_vst_refiller (void *arg) +PluginSelector::btn_add_clicked() { - ((PluginSelector *) arg)->vst_refiller (); + if (plugin_display.get_selection()->count_selected_rows() == 0) { + /* may happen with ctrl + double-click un-selecting but activating a row */ + return; + } + std::string name; + PluginInfoPtr pi; + TreeModel::Row newrow = *(amodel->append()); + TreeModel::Row row; + + row = *(plugin_display.get_selection()->get_selected()); + name = row[plugin_columns.name]; + pi = row[plugin_columns.plugin]; + + newrow[acols.text] = name; + newrow[acols.plugin] = pi; + + if (!amodel->children().empty()) { + set_response_sensitive (RESPONSE_APPLY, true); + } } void -PluginSelector::vst_refiller () +PluginSelector::btn_remove_clicked() { - guint row; - PluginInfoList &plugs = manager->vst_plugin_info (); - PluginInfoList::iterator i; - char ibuf[16], obuf[16]; - vmodel->clear(); - - // Insert into GTK list - for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) { + TreeModel::iterator iter = added_list.get_selection()->get_selected(); - snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs); - snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs); - - Gtk::TreeModel::Row newrow = *(vmodel->append()); - newrow[vcols.name] = (*i)->name.c_str(); - newrow[vcols.ins] = ibuf; - newrow[vcols.outs] = obuf; - newrow[vcols.plugin] = *i; + amodel->erase(iter); + if (amodel->children().empty()) { + set_response_sensitive (RESPONSE_APPLY, false); } - vmodel->set_sort_column (0, Gtk::SORT_ASCENDING); } void -PluginSelector::vst_display_selection_changed() +PluginSelector::display_selection_changed() { - if (vst_display.get_selection()->count_selected_rows() != 0) { + tag_entry_connection.block (); + if (plugin_display.get_selection()->count_selected_rows() != 0) { + + /* a plugin row is selected; allow the user to edit the "tags" on it. */ + TreeModel::Row row = *(plugin_display.get_selection()->get_selected()); + string tags = manager.get_tags_as_string (row[plugin_columns.plugin]); + tag_entry->set_text (tags); + + tag_entry->set_sensitive (true); + tag_reset_button->set_sensitive (true); btn_add->set_sensitive (true); + } else { + tag_entry->set_text (""); + + tag_entry->set_sensitive (false); + tag_reset_button->set_sensitive (false); btn_add->set_sensitive (false); } + tag_entry_connection.unblock (); +} + +void +PluginSelector::added_list_selection_changed() +{ + if (added_list.get_selection()->count_selected_rows() != 0) { + btn_remove->set_sensitive (true); + } else { + btn_remove->set_sensitive (false); + } +} + +int +PluginSelector::run () +{ + ResponseType r; + TreeModel::Children::iterator i; + + bool finish = false; + + while (!finish) { + + SelectedPlugins plugins; + r = (ResponseType) Dialog::run (); + + switch (r) { + case RESPONSE_APPLY: + for (i = amodel->children().begin(); i != amodel->children().end(); ++i) { + PluginInfoPtr pp = (*i)[acols.plugin]; + PluginPtr p = load_plugin (pp); + if (p) { + plugins.push_back (p); + } else { + MessageDialog msg (string_compose (_("The plugin \"%1\" could not be loaded\n\nSee the Log window for more details (maybe)"), pp->name)); + msg.run (); + } + } + if (interested_object && !plugins.empty()) { + finish = !interested_object->use_plugins (plugins); + } + + break; + + default: + finish = true; + break; + } + } + + + hide(); + amodel->clear(); + interested_object = 0; - current_selection = ARDOUR::VST; + if (_need_tag_save) { + manager.save_tags(); + } + + if (_need_status_save) { + manager.save_statuses(); + } + + if ( _need_tag_save || _need_status_save || _need_menu_rebuild ) { + manager.PluginListChanged(); //emit signal + } + + return (int) r; } -#endif //VST_SUPPORT +void +PluginSelector::search_clear_button_clicked () +{ + search_entry.set_text (""); +} -#ifdef HAVE_COREAUDIO +void +PluginSelector::tag_reset_button_clicked () +{ + if (plugin_display.get_selection()->count_selected_rows() != 0) { + TreeModel::Row row = *(plugin_display.get_selection()->get_selected()); + ARDOUR::PluginInfoPtr pi = row[plugin_columns.plugin]; + manager.reset_tags (pi); + display_selection_changed (); + _need_tag_save = true; + _need_menu_rebuild = true; + } +} void -PluginSelector::_au_refiller (void *arg) +PluginSelector::search_entry_changed () { - ((PluginSelector *) arg)->au_refiller (); + set_sensitive_widgets(); + if (search_entry.get_text().empty()) { + refill (); + } } void -PluginSelector::au_refiller () +PluginSelector::tag_entry_changed () { - guint row; - PluginInfoList plugs (AUPluginInfo::discover ()); - PluginInfoList::iterator i; - char ibuf[16], obuf[16]; - aumodel->clear(); - - // Insert into GTK list - for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) { + if (plugin_display.get_selection()->count_selected_rows() != 0) { + TreeModel::Row row = *(plugin_display.get_selection()->get_selected()); + + ARDOUR::PluginInfoPtr pi = row[plugin_columns.plugin]; + manager.set_tags (pi->type, pi->unique_id, tag_entry->get_text(), pi->name, PluginManager::FromGui); - snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs); - snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs); - - Gtk::TreeModel::Row newrow = *(aumodel->append()); - newrow[aucols.name] = (*i)->name.c_str(); - newrow[aucols.ins] = ibuf; - newrow[aucols.outs] = obuf; - newrow[aucols.plugin] = *i; + _need_tag_save = true; + _need_menu_rebuild = true; } - aumodel->set_sort_column (0, Gtk::SORT_ASCENDING); } void -PluginSelector::au_display_selection_changed() +PluginSelector::tags_changed (PluginType t, std::string unique_id, std::string tags) { - if (au_display.get_selection()->count_selected_rows() != 0) { - btn_add->set_sensitive (true); - } else { - btn_add->set_sensitive (false); + if (plugin_display.get_selection()->count_selected_rows() != 0) { + TreeModel::Row row = *(plugin_display.get_selection()->get_selected()); + if (tags.length() > 32) { + tags = tags.substr (0, 32); + tags.append ("..."); + } + row[plugin_columns.tags] = tags; } - - current_selection = ARDOUR::AudioUnit; } -#endif //HAVE_COREAUDIO +void +PluginSelector::plugin_status_changed (PluginType t, std::string uid, PluginManager::PluginStatusType stat) +{ + Gtk::TreeModel::iterator i; + for (i = plugin_model->children().begin(); i != plugin_model->children().end(); ++i) { + PluginInfoPtr pp = (*i)[plugin_columns.plugin]; + if ((pp->type == t) && (pp->unique_id == uid)) { + (*i)[plugin_columns.favorite] = (stat == PluginManager::Favorite) ? true : false; + (*i)[plugin_columns.hidden] = (stat == PluginManager::Hidden) ? true : false; + + /* if plug was hidden, remove it from the view */ + if (stat == PluginManager::Hidden) { + if (!_fil_hidden_radio->get_active() && !_fil_all_radio->get_active()) { + plugin_model->erase(i); + } + } else if (_fil_hidden_radio->get_active()) { + plugin_model->erase(i); + } + /* if no longer a favorite, remove it from the view */ + if (stat != PluginManager::Favorite && _fil_favorites_radio->get_active()) { + plugin_model->erase(i); + } + + return; + } + } +} void -PluginSelector::use_plugin (PluginInfoPtr pi) +PluginSelector::on_show () { - if (session == 0) { - return; + ArdourDialog::on_show (); + search_entry.grab_focus (); + + refill (); + + _need_tag_save = false; + _need_status_save = false; + _need_menu_rebuild = false; +} + +struct PluginMenuCompareByCreator { + bool operator() (PluginInfoPtr a, PluginInfoPtr b) const { + int cmp; + + cmp = cmp_nocase_utf8 (a->creator, b->creator); + + if (cmp < 0) { + return true; + } else if (cmp == 0) { + /* same creator ... compare names */ + if (cmp_nocase_utf8 (a->name, b->name) < 0) { + return true; + } + } + return false; } +}; - PluginPtr plugin = pi->load (*session); +struct PluginMenuCompareByName { + bool operator() (PluginInfoPtr a, PluginInfoPtr b) const { + int cmp; - if (plugin) { - PluginCreated (plugin); + cmp = cmp_nocase_utf8 (a->name, b->name); + + if (cmp < 0) { + return true; + } else if (cmp == 0) { + /* same name ... compare type */ + if (a->type < b->type) { + return true; + } + } + return false; } +}; + +/** @return Plugin menu. The caller should not delete it */ +Gtk::Menu* +PluginSelector::plugin_menu() +{ + return _plugin_menu; } void -PluginSelector::btn_add_clicked() +PluginSelector::build_plugin_menu () { - std::string name; - PluginInfoPtr pi; - Gtk::TreeModel::Row newrow = *(amodel->append()); - - Gtk::TreeModel::Row row; - - switch (current_selection) { - case ARDOUR::LADSPA: - row = *(ladspa_display.get_selection()->get_selected()); - name = row[lcols.name]; - pi = row[lcols.plugin]; - break; - case ARDOUR::VST: -#ifdef VST_SUPPORT - row = *(vst_display.get_selection()->get_selected()); - name = row[vcols.name]; - pi = row[vcols.plugin]; + PluginInfoList all_plugs; + + all_plugs.insert (all_plugs.end(), manager.ladspa_plugin_info().begin(), manager.ladspa_plugin_info().end()); + all_plugs.insert (all_plugs.end(), manager.lua_plugin_info().begin(), manager.lua_plugin_info().end()); +#ifdef WINDOWS_VST_SUPPORT + all_plugs.insert (all_plugs.end(), manager.windows_vst_plugin_info().begin(), manager.windows_vst_plugin_info().end()); #endif - break; - case ARDOUR::AudioUnit: -#ifdef HAVE_COREAUDIO - row = *(au_display.get_selection()->get_selected()); - name = row[aucols.name]; - pi = row[aucols.plugin]; +#ifdef LXVST_SUPPORT + all_plugs.insert (all_plugs.end(), manager.lxvst_plugin_info().begin(), manager.lxvst_plugin_info().end()); #endif - break; - default: - error << "Programming error. Unknown plugin selected." << endmsg; - return; +#ifdef MACVST_SUPPORT + all_plugs.insert (all_plugs.end(), manager.mac_vst_plugin_info().begin(), manager.mac_vst_plugin_info().end()); +#endif +#ifdef AUDIOUNIT_SUPPORT + all_plugs.insert (all_plugs.end(), manager.au_plugin_info().begin(), manager.au_plugin_info().end()); +#endif +#ifdef LV2_SUPPORT + all_plugs.insert (all_plugs.end(), manager.lv2_plugin_info().begin(), manager.lv2_plugin_info().end()); +#endif + + using namespace Menu_Helpers; + + delete _plugin_menu; + + _plugin_menu = manage (new Menu); + _plugin_menu->set_name("ArdourContextMenu"); + + MenuList& items = _plugin_menu->items(); + items.clear (); + + Gtk::Menu* favs = create_favs_menu(all_plugs); + items.push_back (MenuElem (_("Favorites"), *manage (favs))); + + items.push_back (MenuElem (_("Plugin Manager..."), sigc::mem_fun (*this, &PluginSelector::show_manager))); + items.push_back (SeparatorElem ()); + + Menu* by_creator = create_by_creator_menu(all_plugs); + items.push_back (MenuElem (_("By Creator"), *manage (by_creator))); + + Menu* by_tags = create_by_tags_menu(all_plugs); + items.push_back (MenuElem (_("By Tags"), *manage (by_tags))); +} + +string +GetPluginTypeStr(PluginInfoPtr info) +{ + string type; + + switch (info->type) { + case LADSPA: + type = X_(" (LADSPA)"); + break; + case AudioUnit: + type = X_(" (AU)"); + break; + case LV2: + type = X_(" (LV2)"); + break; + case Windows_VST: + case LXVST: + case MacVST: + type = X_(" (VST)"); + break; + case Lua: + type = X_(" (Lua)"); + break; } - newrow[acols.text] = name; - newrow[acols.plugin] = pi; + return type; +} - if (!amodel->children().empty()) { - set_response_sensitive (RESPONSE_APPLY, true); +Gtk::Menu* +PluginSelector::create_favs_menu (PluginInfoList& all_plugs) +{ + using namespace Menu_Helpers; + + Menu* favs = new Menu(); + favs->set_name("ArdourContextMenu"); + + PluginMenuCompareByName cmp_by_name; + all_plugs.sort (cmp_by_name); + + for (PluginInfoList::const_iterator i = all_plugs.begin(); i != all_plugs.end(); ++i) { + if (manager.get_status (*i) == PluginManager::Favorite) { + string typ = GetPluginTypeStr(*i); + MenuElem elem ((*i)->name + typ, (sigc::bind (sigc::mem_fun (*this, &PluginSelector::plugin_chosen_from_menu), *i))); + elem.get_child()->set_use_underline (false); + favs->items().push_back (elem); + } } + return favs; } -void -PluginSelector::btn_remove_clicked() +Gtk::Menu* +PluginSelector::create_by_creator_menu (ARDOUR::PluginInfoList& all_plugs) { - Gtk::TreeModel::iterator iter = added_list.get_selection()->get_selected(); - - amodel->erase(iter); - if (amodel->children().empty()) { - set_response_sensitive (RESPONSE_APPLY, false); + _inhibit_refill = true; + _fil_creator_combo.clear_items (); + _fil_creator_combo.append_text_item (_("Show All Creators")); + _fil_creator_combo.set_text (_("Show All Creators")); + _inhibit_refill = false; + + using namespace Menu_Helpers; + + typedef std::map SubmenuMap; + SubmenuMap creator_submenu_map; + + Menu* by_creator = new Menu(); + by_creator->set_name("ArdourContextMenu"); + + MenuList& by_creator_items = by_creator->items(); + PluginMenuCompareByCreator cmp_by_creator; + all_plugs.sort (cmp_by_creator); + + for (PluginInfoList::const_iterator i = all_plugs.begin(); i != all_plugs.end(); ++i) { + + if (manager.get_status (*i) == PluginManager::Hidden) continue; + + string creator = (*i)->creator; + + /* If there were too few characters to create a + * meaningful name, mark this creator as 'Unknown' + */ + if (creator.length() < 2) { + creator = "Unknown"; + } + + SubmenuMap::iterator x; + Gtk::Menu* submenu; + if ((x = creator_submenu_map.find (creator)) != creator_submenu_map.end()) { + submenu = x->second; + } else { + + _fil_creator_combo.append_text_item (creator); + + submenu = new Gtk::Menu; + by_creator_items.push_back (MenuElem (creator, *manage (submenu))); + creator_submenu_map.insert (pair (creator, submenu)); + submenu->set_name("ArdourContextMenu"); + } + string typ = GetPluginTypeStr(*i); + MenuElem elem ((*i)->name+typ, (sigc::bind (sigc::mem_fun (*this, &PluginSelector::plugin_chosen_from_menu), *i))); + elem.get_child()->set_use_underline (false); + submenu->items().push_back (elem); } + + return by_creator; } -void -PluginSelector::btn_update_clicked() -{ - manager->refresh (); - input_refiller (); -#ifdef VST_SUPPORT - vst_refiller (); -#endif -#ifdef HAVE_COREAUDIO - au_refiller (); -#endif +Gtk::Menu* +PluginSelector::create_by_tags_menu (ARDOUR::PluginInfoList& all_plugs) +{ + using namespace Menu_Helpers; + + typedef std::map SubmenuMap; + SubmenuMap tags_submenu_map; + + Menu* by_tags = new Menu(); + by_tags->set_name("ArdourContextMenu"); + MenuList& by_tags_items = by_tags->items(); + + std::vector all_tags = manager.get_all_tags (PluginManager::NoHidden); + for (vector::iterator t = all_tags.begin(); t != all_tags.end(); ++t) { + Gtk::Menu *submenu = new Gtk::Menu; + by_tags_items.push_back (MenuElem (*t, *manage (submenu))); + tags_submenu_map.insert (pair (*t, submenu)); + submenu->set_name("ArdourContextMenu"); + } + + PluginMenuCompareByName cmp_by_name; + all_plugs.sort (cmp_by_name); + + for (PluginInfoList::const_iterator i = all_plugs.begin(); i != all_plugs.end(); ++i) { + + if (manager.get_status (*i) == PluginManager::Hidden) continue; + + /* for each tag in the plugins tag list, add it to that submenu */ + vector tokens = manager.get_tags(*i); + for (vector::iterator t = tokens.begin(); t != tokens.end(); ++t) { + SubmenuMap::iterator x; + Gtk::Menu* submenu; + if ((x = tags_submenu_map.find (*t)) != tags_submenu_map.end()) { + submenu = x->second; + string typ = GetPluginTypeStr(*i); + MenuElem elem ((*i)->name + typ, (sigc::bind (sigc::mem_fun (*this, &PluginSelector::plugin_chosen_from_menu), *i))); + elem.get_child()->set_use_underline (false); + submenu->items().push_back (elem); + } + } + } + return by_tags; } void -PluginSelector::ladspa_display_selection_changed() +PluginSelector::plugin_chosen_from_menu (const PluginInfoPtr& pi) { - if (ladspa_display.get_selection()->count_selected_rows() != 0) { - btn_add->set_sensitive (true); - } else { - btn_add->set_sensitive (false); + PluginPtr p = load_plugin (pi); + + if (p && interested_object) { + SelectedPlugins plugins; + plugins.push_back (p); + interested_object->use_plugins (plugins); } - - current_selection = ARDOUR::LADSPA; + + interested_object = 0; } void -PluginSelector::added_list_selection_changed() +PluginSelector::favorite_changed (const std::string& path) { - if (added_list.get_selection()->count_selected_rows() != 0) { - btn_remove->set_sensitive (true); - } else { - btn_remove->set_sensitive (false); - } + PluginInfoPtr pi; + + if (in_row_change) { + return; + } + + in_row_change = true; + + TreeModel::iterator iter = plugin_model->get_iter (path); + + if (iter) { + + bool favorite = !(*iter)[plugin_columns.favorite]; + + /* change state */ + + PluginManager::PluginStatusType status = (favorite ? PluginManager::Favorite : PluginManager::Normal); + + /* save new statuses list */ + + pi = (*iter)[plugin_columns.plugin]; + + manager.set_status (pi->type, pi->unique_id, status); + + _need_status_save = true; + _need_menu_rebuild = true; + } + in_row_change = false; } -int -PluginSelector::run () +void +PluginSelector::hidden_changed (const std::string& path) { - ResponseType r; - TreeModel::Children::iterator i; + PluginInfoPtr pi; - r = (ResponseType) Dialog::run (); + if (in_row_change) { + return; + } - switch (r) { - case RESPONSE_APPLY: - for (i = amodel->children().begin(); i != amodel->children().end(); ++i) { - use_plugin ((*i)[acols.plugin]); - } - break; + in_row_change = true; - default: - break; - } + TreeModel::iterator iter = plugin_model->get_iter (path); - cleanup (); + if (iter) { - return (int) r; + bool hidden = !(*iter)[plugin_columns.hidden]; + + /* change state */ + + PluginManager::PluginStatusType status = (hidden ? PluginManager::Hidden : PluginManager::Normal); + + /* save new statuses list */ + + pi = (*iter)[plugin_columns.plugin]; + + manager.set_status (pi->type, pi->unique_id, status); + + _need_status_save = true; + _need_menu_rebuild = true; + } + in_row_change = false; } void -PluginSelector::cleanup () +PluginSelector::show_manager () { - hide(); - amodel->clear(); + show_all(); + run (); +} + +void +PluginSelector::set_interested_object (PluginInterestedObject& obj) +{ + interested_object = &obj; }