X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fplugin_selector.cc;h=c67af473a0723f5b13eeb1db58af116487527a8f;hb=b976bf8986290e8f4812a50e7fdd98b9cbeb4249;hp=dee19256a79f9558a2a137f9451f08cb164b374a;hpb=d38e2213d79b1c8952c776a3b60f7709457edc0c;p=ardour.git diff --git a/gtk2_ardour/plugin_selector.cc b/gtk2_ardour/plugin_selector.cc index dee19256a7..c67af473a0 100644 --- a/gtk2_ardour/plugin_selector.cc +++ b/gtk2_ardour/plugin_selector.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2000 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,403 +16,1118 @@ 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 "pbd/convert.h" + +#include "ardour/plugin_manager.h" +#include "ardour/plugin.h" +#include "ardour/utils.h" -#include "ardour_ui.h" #include "plugin_selector.h" #include "gui_thread.h" +#include "tooltips.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace ARDOUR; +using namespace PBD; +using namespace Gtk; +using namespace std; +using namespace ARDOUR_UI_UTILS; -static const gchar *i_titles[] = { - N_("Available LADSPA plugins"), - N_("Type"), - N_("# Inputs"), - N_("# Outputs"), - 0 -}; - -#ifdef VST_SUPPORT -static const gchar *vst_titles[] = { - N_("Available VST plugins"), - N_("# Inputs"), - N_("# Outputs"), +static const char* _filter_mode_strings[] = { + N_("Name contains"), + N_("Type contains"), + N_("Category contains"), + N_("Author contains"), + N_("Library contains"), + N_("Favorites only"), + N_("Hidden only"), 0 }; -#endif -static const gchar *o_titles[] = { - N_("To be added"), - 0 -}; +PluginSelector::PluginSelector (PluginManager& mgr) + : ArdourDialog (_("Plugin Manager"), true, false) + , filter_button (Stock::CLEAR) + , fil_hidden_button (ArdourButton::led_default_elements) + , fil_instruments_button (ArdourButton::default_elements) + , fil_analysis_button (ArdourButton::default_elements) + , fil_utils_button (ArdourButton::default_elements) + , manager (mgr) + , _show_hidden (false) + , _show_instruments (Gtkmm2ext::ImplicitActive) + , _show_analysers (Gtkmm2ext::Off) + , _show_utils (Gtkmm2ext::Off) -PluginSelector::PluginSelector (PluginManager *mgr) - : ArdourDialog ("plugin selector"), - ladspa_display (_input_refiller, this, internationalize (i_titles), false, true), -#ifdef VST_SUPPORT - vst_display (_vst_refiller, this, internationalize (vst_titles), false, true), -#endif - o_selector (_output_refiller, this, internationalize (o_titles), false, true) { - set_position (Gtk::WIN_POS_MOUSE); set_name ("PluginSelectorWindow"); - set_title (_("ardour: plugins")); - set_modal(true); add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK); - manager = mgr; - session = 0; - o_selected_plug = -1; - i_selected_plug = 0; + _plugin_menu = 0; + in_row_change = false; + + manager.PluginListChanged.connect (plugin_list_changed_connection, invalidator (*this), boost::bind (&PluginSelector::build_plugin_menu, this), gui_context()); + manager.PluginListChanged.connect (plugin_list_changed_connection, invalidator (*this), boost::bind (&PluginSelector::refill, this), gui_context()); + manager.PluginStatusesChanged.connect (plugin_list_changed_connection, invalidator (*this), boost::bind (&PluginSelector::build_plugin_menu, this), gui_context()); + manager.PluginStatusesChanged.connect (plugin_list_changed_connection, invalidator (*this), boost::bind (&PluginSelector::refill, this), gui_context()); + build_plugin_menu (); + + 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 (_("Available Plugins"), plugin_columns.name); + plugin_display.append_column (_("Type"), plugin_columns.type_name); + plugin_display.append_column (_("Category"), plugin_columns.category); + plugin_display.append_column (_("Creator"), plugin_columns.creator); + plugin_display.append_column (_("# Audio In"),plugin_columns.audio_ins); + plugin_display.append_column (_("# Audio Out"), plugin_columns.audio_outs); + plugin_display.append_column (_("# MIDI In"),plugin_columns.midi_ins); + plugin_display.append_column (_("# MIDI Out"), plugin_columns.midi_outs); + 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); + + 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)); - Gtk::Button *btn_add = manage(new Gtk::Button(_("Add"))); - ARDOUR_UI::instance()->tooltips().set_tip(*btn_add, _("Add a plugin to the effect list")); - Gtk::Button *btn_remove = manage(new Gtk::Button(_("Remove"))); - ARDOUR_UI::instance()->tooltips().set_tip(*btn_remove, _("Remove a plugin from the effect list")); - Gtk::Button *btn_ok = manage(new Gtk::Button(_("OK"))); - Gtk::Button *btn_cancel = manage(new Gtk::Button(_("Cancel"))); + 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"), acols.text); + added_list.set_headers_visible (true); + added_list.set_reorderable (false); + + for (int i = 0; i <=8; i++) { + Gtk::TreeView::Column* column = plugin_display.get_column(i); + column->set_sort_column(i); + } - Gtk::Button *btn_update = manage(new Gtk::Button(_("Update"))); - ARDOUR_UI::instance()->tooltips().set_tip(*btn_update, _("Update available plugins")); + 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)); + 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); + set_tooltip(*btn_remove, _("Remove a plugin from the effect list")); - btn_ok->set_name("PluginSelectorButton"); - btn_cancel->set_name("PluginSelectorButton"); btn_add->set_name("PluginSelectorButton"); btn_remove->set_name("PluginSelectorButton"); - - Gtk::Table* table = manage(new Gtk::Table(7, 10)); + + + Gtk::Table* table = manage(new Gtk::Table(7, 11)); table->set_size_request(750, 500); - table->attach(notebook, 0, 7, 0, 5); - table->attach(*btn_add, 1, 2, 5, 6, Gtk::FILL, 0, 5, 5); - table->attach(*btn_remove, 3, 4, 5, 6, Gtk::FILL, 0, 5, 5); - table->attach(*btn_update, 5, 6, 5, 6, Gtk::FILL, 0, 5, 5); + Gtk::Table* filter_table = manage(new Gtk::Table(2, 5)); - table->attach(o_selector, 0, 7, 7, 9); - table->attach(*btn_ok, 1, 3, 9, 10, Gtk::FILL, 0, 5, 5); - table->attach(*btn_cancel, 3, 4, 9, 10, Gtk::FILL, 0, 5, 5); - add (*table); + fil_hidden_button.set_name ("pluginlist hide button"); + fil_hidden_button.set_text (_("Show Hidden")); + fil_hidden_button.set_active (_show_hidden); + set_tooltip (fil_hidden_button, _("Include hidden plugins in list.")); - using namespace Gtk::Notebook_Helpers; - notebook.pages().push_back (TabElem (ladspa_display, _("LADSPA"))); -#ifdef VST_SUPPORT - if (Config->get_use_vst()) { - notebook.pages().push_back (TabElem (vst_display, _("VST"))); - } -#endif + fil_instruments_button.set_name ("pluginlist filter button"); + fil_instruments_button.set_text (_("Instruments")); + fil_instruments_button.set_active_state (_show_instruments); + set_tooltip (fil_instruments_button, _("Cycle display of instrument plugins (if any).")); + + fil_analysis_button.set_name ("pluginlist filter button"); + fil_analysis_button.set_text (_("Analyzers")); + fil_analysis_button.set_active_state (_show_analysers); + set_tooltip (fil_analysis_button, _("Cycle display of analysis plugins (if any).")); + + fil_utils_button.set_name ("pluginlist filter button"); + fil_utils_button.set_text (_("Utils")); + fil_utils_button.set_active_state (_show_utils); + set_tooltip (fil_utils_button, _("Cycle display of utility plugins (if any).")); + + vector filter_strings = I18N (_filter_mode_strings); + Gtkmm2ext::set_popdown_strings (filter_mode, filter_strings); + filter_mode.set_active_text (filter_strings.front()); + + fil_hidden_button.signal_button_release_event().connect (sigc::mem_fun(*this, &PluginSelector::fil_hidden_button_release), false); + fil_instruments_button.signal_button_release_event().connect (sigc::mem_fun(*this, &PluginSelector::fil_instruments_button_release), false); + fil_analysis_button.signal_button_release_event().connect (sigc::mem_fun(*this, &PluginSelector::fil_analysis_button_release), false); + fil_utils_button.signal_button_release_event().connect (sigc::mem_fun(*this, &PluginSelector::fil_utils_button_release), false); + + filter_entry.signal_changed().connect (sigc::mem_fun (*this, &PluginSelector::filter_entry_changed)); + filter_button.signal_clicked().connect (sigc::mem_fun (*this, &PluginSelector::filter_button_clicked)); + filter_mode.signal_changed().connect (sigc::mem_fun (*this, &PluginSelector::filter_mode_changed)); + + filter_table->attach (filter_mode, 0, 1, 0, 1, FILL, FILL); + filter_table->attach (filter_entry, 1, 4, 0, 1, FILL|EXPAND, FILL); + filter_table->attach (filter_button, 4, 5, 0, 1, FILL, FILL); + + filter_table->attach (fil_hidden_button, 1, 2, 1, 2, FILL, FILL); + filter_table->attach (fil_instruments_button, 2, 3, 1, 2, FILL, FILL); + filter_table->attach (fil_analysis_button, 3, 4, 1, 2, FILL, FILL); + filter_table->attach (fil_utils_button, 4, 5, 1, 2, FILL, FILL); + + filter_table->set_border_width (4); + filter_table->set_col_spacings (2); + filter_table->set_row_spacings (4); + + Frame* filter_frame = manage (new Frame); + filter_frame->set_name ("BaseFrame"); + filter_frame->set_label (_("Filter")); + filter_frame->add (*filter_table); + + filter_frame->show_all (); + + HBox* side_by_side = manage (new HBox); + VBox* right_side = manage (new VBox); + + table->attach (scroller, 0, 7, 0, 5); + table->attach (*filter_frame, 0, 7, 6, 7, FILL|EXPAND, FILL, 5, 5); + + right_side->pack_start (ascroller); + + HBox* add_remove = manage (new HBox); + add_remove->pack_start (*btn_add, true, true); + add_remove->pack_start (*btn_remove, true, true); + + right_side->pack_start (*add_remove, false, false); + right_side->set_size_request (200, -1); + + side_by_side->pack_start (*table); + side_by_side->pack_start (*right_side); + + 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 (*side_by_side); table->set_name("PluginSelectorTable"); - //ladspa_display.set_name("PluginSelectorDisplay"); - ladspa_display.clist().set_name("PluginSelectorList"); - o_selector.clist().set_name("PluginSelectorList"); - - ladspa_display.clist().column_titles_active(); - ladspa_display.clist().column(0).set_auto_resize (false); - ladspa_display.clist().column(0).set_width(470); - - ladspa_display.clist().column(1).set_auto_resize (true); - o_selector.clist().column(0).set_auto_resize (true); - - ladspa_display.selection_made.connect (mem_fun(*this, &PluginSelector::i_plugin_selected)); - ladspa_display.choice_made.connect(mem_fun(*this, &PluginSelector::i_plugin_chosen)); - ladspa_display.clist().click_column.connect(bind (mem_fun(*this, &PluginSelector::column_clicked), ladspa_display.clist().gobj())); -#ifdef VST_SUPPORT - if (Config->get_use_vst()) { - vst_display.selection_made.connect (mem_fun(*this, &PluginSelector::i_plugin_selected)); - vst_display.choice_made.connect(mem_fun(*this, &PluginSelector::i_plugin_chosen)); - vst_display.clist().click_column.connect(bind (mem_fun(*this, &PluginSelector::column_clicked), vst_display.clist().gobj())); - } -#endif - o_selector.selection_made.connect(mem_fun(*this, &PluginSelector::o_plugin_selected)); - o_selector.choice_made.connect(mem_fun(*this,&PluginSelector::o_plugin_chosen)); - btn_update-.signal_clicked().connect (mem_fun(*this, &PluginSelector::btn_update_clicked)); - btn_add->clicked.connect(mem_fun(*this, &PluginSelector::btn_add_clicked)); - btn_remove->clicked.connect(mem_fun(*this, &PluginSelector::btn_remove_clicked)); - btn_ok->clicked.connect(mem_fun(*this, &PluginSelector::btn_ok_clicked)); - btn_cancel->clicked.connect(mem_fun(*this,&PluginSelector::btn_cancel_clicked)); - delete_event.connect (mem_fun(*this, &PluginSelector::wm_close)); + plugin_display.set_name("PluginSelectorDisplay"); + //plugin_display.set_name("PluginSelectorList"); + added_list.set_name("PluginSelectorList"); + + 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)); + plugin_display.grab_focus(); + 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)); + + refill (); +} + +PluginSelector::~PluginSelector () +{ + delete _plugin_menu; } void -PluginSelector::set_session (Session* s) +PluginSelector::row_activated(Gtk::TreeModel::Path, Gtk::TreeViewColumn*) { - ENSURE_GUI_THREAD(bind (mem_fun(*this, &PluginSelector::set_session), s)); - - session = s; + btn_add_clicked(); +} - if (session) { - session->going_away.connect (bind (mem_fun(*this, &PluginSelector::set_session), static_cast (0))); +void +PluginSelector::added_row_clicked(GdkEventButton* event) +{ + if (event->type == GDK_2BUTTON_PRESS) + btn_remove_clicked(); +} + +static bool is_analyzer (const PluginInfoPtr& info) { + // Anaylsis, Analyzer are for backwards compatibility (vst cache) + return info->in_category ("Analyser") || info->in_category ("Anaylsis") || info->in_category ("Analyzer"); +} + +static bool is_util (const PluginInfoPtr& info) { + // all MIDI plugins which are not Instruments are Utils. + return info->in_category ("Utility") || info->in_category ("MIDI") || info->in_category ("Generator"); +} + +bool +PluginSelector::show_this_plugin (const PluginInfoPtr& info, const std::string& filterstr) +{ + std::string compstr; + std::string mode = filter_mode.get_active_text (); + + if (mode == _("Favorites only")) { + return manager.get_status (info) == PluginManager::Favorite; + } + + if (mode == _("Hidden only")) { + return manager.get_status (info) == PluginManager::Hidden; + } + + if (!_show_hidden && manager.get_status (info) == PluginManager::Hidden) { + return false; } + + if (_show_instruments == Gtkmm2ext::Off && info->is_instrument()) { + return false; + } + if (_show_analysers == Gtkmm2ext::Off && is_analyzer (info)) { + return false; + } + if (_show_utils == Gtkmm2ext::Off && is_util (info)) { + return false; + } + + /* NB once lilv_node_as_string() does honor translation AND + * the lv2 onthology provides localized class name, + * PluginInfo will need methods for Util & Analysis. + */ + bool exp_ok = false; + if (_show_instruments == Gtkmm2ext::ExplicitActive && info->is_instrument()) { + exp_ok = true; + } + if (_show_analysers == Gtkmm2ext::ExplicitActive && is_analyzer(info)) { + exp_ok = true; + } + if (_show_utils == Gtkmm2ext::ExplicitActive && is_util (info)) { + exp_ok = true; + } + if (_show_instruments == Gtkmm2ext::ExplicitActive || _show_analysers == Gtkmm2ext::ExplicitActive || _show_utils == Gtkmm2ext::ExplicitActive) { + if (!exp_ok) { + return false; + } + } + + if (!filterstr.empty()) { + + if (mode == _("Name contains")) { + compstr = info->name; + } else if (mode == _("Category contains")) { + compstr = info->category; + } else if (mode == _("Type contains")) { + + switch (info->type) { + case LADSPA: + compstr = X_("LADSPA"); + break; + case AudioUnit: + compstr = X_("AudioUnit"); + break; + case LV2: + compstr = X_("LV2"); + break; + case Windows_VST: + compstr = X_("VST"); + break; + case LXVST: + compstr = X_("LXVST"); + break; + case MacVST: + compstr = X_("MacVST"); + break; + case Lua: + compstr = X_("Lua"); + break; + } + + } else if (mode == _("Author contains")) { + compstr = info->creator; + } else if (mode == _("Library contains")) { + compstr = info->path; + } + + if (compstr.empty()) { + return false; + } + + transform (compstr.begin(), compstr.end(), compstr.begin(), ::toupper); + + if (compstr.find (filterstr) != string::npos) { + return true; + } else { + return false; + } + } + + return true; } void -PluginSelector::_input_refiller (Gtk::CList &list, void *arg) +PluginSelector::setup_filter_string (string& filterstr) { - ((PluginSelector *) arg)->input_refiller (list); + filterstr = filter_entry.get_text (); + transform (filterstr.begin(), filterstr.end(), filterstr.begin(), ::toupper); } void -PluginSelector::_output_refiller (Gtk::CList &list, void *arg) +PluginSelector::refill () { - ((PluginSelector *) arg)->output_refiller (list); + std::string filterstr; + + in_row_change = true; + + plugin_model->clear (); + + setup_filter_string (filterstr); + + ladspa_refiller (filterstr); + lv2_refiller (filterstr); + vst_refiller (filterstr); + lxvst_refiller (filterstr); + mac_vst_refiller (filterstr); + au_refiller (filterstr); + lua_refiller (filterstr); + + in_row_change = false; } -int compare(const void *left, const void *right) +void +PluginSelector::refiller (const PluginInfoList& plugs, const::std::string& filterstr, const char* type) { - return strcmp(*((char**)left), *((char**)right)); + char buf[16]; + + for (PluginInfoList::const_iterator i = plugs.begin(); i != plugs.end(); ++i) { + + if (show_this_plugin (*i, filterstr)) { + + 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); + newrow[plugin_columns.name] = (*i)->name; + newrow[plugin_columns.type_name] = type; + newrow[plugin_columns.category] = (*i)->category; + + 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); + } + + newrow[plugin_columns.creator] = creator; + + if ((*i)->reconfigurable_io ()) { + newrow[plugin_columns.audio_ins] = _("variable"); + newrow[plugin_columns.midi_ins] = _("variable"); + newrow[plugin_columns.audio_outs] = _("variable"); + newrow[plugin_columns.midi_outs] = _("variable"); + } else { + snprintf (buf, sizeof(buf), "%d", (*i)->n_inputs.n_audio()); + newrow[plugin_columns.audio_ins] = buf; + snprintf (buf, sizeof(buf), "%d", (*i)->n_inputs.n_midi()); + newrow[plugin_columns.midi_ins] = buf; + + snprintf (buf, sizeof(buf), "%d", (*i)->n_outputs.n_audio()); + newrow[plugin_columns.audio_outs] = buf; + snprintf (buf, sizeof(buf), "%d", (*i)->n_outputs.n_midi()); + newrow[plugin_columns.midi_outs] = buf; + } + + newrow[plugin_columns.plugin] = *i; + } + } } void -PluginSelector::input_refiller (Gtk::CList &clist) +PluginSelector::ladspa_refiller (const std::string& filterstr) { - const gchar *rowdata[4]; - guint row; - list &plugs = manager->ladspa_plugin_info (); - list::iterator i; - char ibuf[16], obuf[16]; - - // Insert into GTK list - for (row = 0, i=plugs.begin(); i != plugs.end(); ++i, ++row) { - rowdata[0] = (*i)->name.c_str(); - rowdata[1] = (*i)->category.c_str(); + refiller (manager.ladspa_plugin_info(), filterstr, "LADSPA"); +} - snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs); - snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs); - rowdata[2] = ibuf; - rowdata[3] = obuf; - - clist.insert_row (row, rowdata); - clist.rows().back().set_data (*i); - } +void +PluginSelector::lua_refiller (const std::string& filterstr) +{ + refiller (manager.lua_plugin_info(), filterstr, "Lua"); +} - clist.set_sort_column (0); - clist.sort (); +void +PluginSelector::lv2_refiller (const std::string& filterstr) +{ +#ifdef LV2_SUPPORT + refiller (manager.lv2_plugin_info(), filterstr, "LV2"); +#endif } -#ifdef VST_SUPPORT +void +#ifdef WINDOWS_VST_SUPPORT +PluginSelector::vst_refiller (const std::string& filterstr) +#else +PluginSelector::vst_refiller (const std::string&) +#endif +{ +#ifdef WINDOWS_VST_SUPPORT + refiller (manager.windows_vst_plugin_info(), filterstr, "VST"); +#endif +} void -PluginSelector::_vst_refiller (Gtk::CList &list, void *arg) +#ifdef LXVST_SUPPORT +PluginSelector::lxvst_refiller (const std::string& filterstr) +#else +PluginSelector::lxvst_refiller (const std::string&) +#endif { - ((PluginSelector *) arg)->vst_refiller (list); +#ifdef LXVST_SUPPORT + refiller (manager.lxvst_plugin_info(), filterstr, "LXVST"); +#endif } void -PluginSelector::vst_refiller (Gtk::CList &clist) +#ifdef MACVST_SUPPORT +PluginSelector::mac_vst_refiller (const std::string& filterstr) +#else +PluginSelector::mac_vst_refiller (const std::string&) +#endif { - const gchar *rowdata[3]; - guint row; - list &plugs = manager->vst_plugin_info (); - list::iterator i; - char ibuf[16], obuf[16]; - - if (!Config->get_use_vst()) { - return; +#ifdef MACVST_SUPPORT + refiller (manager.mac_vst_plugin_info(), filterstr, "MacVST"); +#endif +} + +void +#ifdef AUDIOUNIT_SUPPORT +PluginSelector::au_refiller (const std::string& filterstr) +#else +PluginSelector::au_refiller (const std::string&) +#endif +{ +#ifdef AUDIOUNIT_SUPPORT + refiller (manager.au_plugin_info(), filterstr, "AU"); +#endif +} + +PluginPtr +PluginSelector::load_plugin (PluginInfoPtr pi) +{ + if (_session == 0) { + return PluginPtr(); } - // Insert into GTK list + return pi->load (*_session); +} + +void +PluginSelector::btn_add_clicked() +{ + 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]; - for (row = 0, i = plugs.begin(); i != plugs.end(); ++i, ++row) { - rowdata[0] = (*i)->name.c_str(); + newrow[acols.text] = name; + newrow[acols.plugin] = pi; - snprintf (ibuf, sizeof(ibuf)-1, "%d", (*i)->n_inputs); - snprintf (obuf, sizeof(obuf)-1, "%d", (*i)->n_outputs); - rowdata[1] = ibuf; - rowdata[2] = obuf; - - clist.insert_row (row, rowdata); - clist.rows().back().set_data (*i); + if (!amodel->children().empty()) { + set_response_sensitive (RESPONSE_APPLY, true); } - - clist.set_sort_column (0); - clist.sort (); } -#endif void -PluginSelector::output_refiller (Gtk::CList &clist) +PluginSelector::btn_remove_clicked() { - const gchar *rowdata[2]; - guint row; - list::iterator i; - - // Insert into GTK list + TreeModel::iterator iter = added_list.get_selection()->get_selected(); - for (row = 0, i = added_plugins.begin(); i != added_plugins.end(); ++i, ++row){ - rowdata[0] = (*i)->name.c_str(); - clist.insert_row (row, rowdata); - clist.rows().back().set_data (*i); + amodel->erase(iter); + if (amodel->children().empty()) { + set_response_sensitive (RESPONSE_APPLY, false); } } void -PluginSelector::i_plugin_chosen (Gtkmm2ext::Selector *selector, - Gtkmm2ext::SelectionResult *res) +PluginSelector::display_selection_changed() { - if (res) { - // get text for name column (0) - i_selected_plug = static_cast (selector->clist().row(res->row).get_data()); - //i_selected_plug = *res->text; + if (plugin_display.get_selection()->count_selected_rows() != 0) { + btn_add->set_sensitive (true); } else { - i_selected_plug = 0; + btn_add->set_sensitive (false); } } void -PluginSelector::i_plugin_selected (Gtkmm2ext::Selector *selector, - Gtkmm2ext::SelectionResult *res) +PluginSelector::added_list_selection_changed() { - if (res) { - added_plugins.push_back (static_cast (selector->clist().row(res->row).get_data())); - //added_plugins.push_back(*(res->text)); - o_selector.rescan(); + 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; + + return (int) r; +} + void -PluginSelector::o_plugin_chosen (Gtkmm2ext::Selector *selector, - Gtkmm2ext::SelectionResult *res) +PluginSelector::filter_button_clicked () { - if (res && res->text) { - o_selected_plug = res->row; + filter_entry.set_text (""); +} + +void +PluginSelector::filter_entry_changed () +{ + refill (); +} + +void +PluginSelector::filter_mode_changed () +{ + std::string mode = filter_mode.get_active_text (); + + if (mode == _("Favorites only") || mode == _("Hidden only")) { + filter_entry.set_sensitive (false); + filter_button.set_sensitive (false); + fil_hidden_button.set_sensitive (false); + fil_instruments_button.set_sensitive (false); + fil_analysis_button.set_sensitive (false); + fil_utils_button.set_sensitive (false); } else { - o_selected_plug = -1; + filter_entry.set_sensitive (true); + filter_button.set_sensitive (true); + fil_hidden_button.set_sensitive (true); + fil_instruments_button.set_sensitive (true); + fil_analysis_button.set_sensitive (true); + fil_utils_button.set_sensitive (true); } + refill (); } void -PluginSelector::o_plugin_selected (Gtkmm2ext::Selector *selector, - Gtkmm2ext::SelectionResult *res) -{ - if(res && res->text){ - gint row = 0; - list::iterator i = added_plugins.begin(); - while (row < res->row){ - i++; - row++; +PluginSelector::on_show () +{ + ArdourDialog::on_show (); + filter_entry.grab_focus (); +} + +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; + } +}; + +struct PluginMenuCompareByName { + bool operator() (PluginInfoPtr a, PluginInfoPtr b) const { + int cmp; + + 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; + } } - added_plugins.erase(i); - o_selector.rescan(); - o_selected_plug = -1; + return false; } +}; + +struct PluginMenuCompareByCategory { + bool operator() (PluginInfoPtr a, PluginInfoPtr b) const { + int cmp; + + cmp = cmp_nocase_utf8 (a->category, b->category); + + if (cmp < 0) { + return true; + } else if (cmp == 0) { + /* same category ... compare names */ + if (cmp_nocase_utf8 (a->name, b->name) < 0) { + return true; + } + } + return false; + } +}; + +/** @return Plugin menu. The caller should not delete it */ +Gtk::Menu* +PluginSelector::plugin_menu() +{ + return _plugin_menu; } void -PluginSelector::use_plugin (PluginInfo* pi) +PluginSelector::build_plugin_menu () { - list::iterator i; + PluginInfoList all_plugs; - if (pi == 0 || session == 0) { - return; + 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 +#ifdef LXVST_SUPPORT + all_plugs.insert (all_plugs.end(), manager.lxvst_plugin_info().begin(), manager.lxvst_plugin_info().end()); +#endif +#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_category = create_by_category_menu(all_plugs); + items.push_back (MenuElem (_("By Category"), *manage (by_category))); +} + +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; + } + + return type; +} + +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; +} + +Gtk::Menu* +PluginSelector::create_by_creator_menu (ARDOUR::PluginInfoList& all_plugs) +{ + 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; + 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); + } + + SubmenuMap::iterator x; + Gtk::Menu* submenu; + if ((x = creator_submenu_map.find (creator)) != creator_submenu_map.end()) { + submenu = x->second; + } else { + 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; +} + +Gtk::Menu* +PluginSelector::create_by_category_menu (ARDOUR::PluginInfoList& all_plugs) +{ + using namespace Menu_Helpers; + + typedef std::map SubmenuMap; + SubmenuMap category_submenu_map; + + Menu* by_category = new Menu(); + by_category->set_name("ArdourContextMenu"); + + MenuList& by_category_items = by_category->items(); + PluginMenuCompareByCategory cmp_by_category; + all_plugs.sort (cmp_by_category); - Plugin *plugin = manager->load (*session, pi); + for (PluginInfoList::const_iterator i = all_plugs.begin(); i != all_plugs.end(); ++i) { - if (plugin) { - PluginCreated (plugin); + if (manager.get_status (*i) == PluginManager::Hidden) continue; + + string category = (*i)->category; + + SubmenuMap::iterator x; + Gtk::Menu* submenu; + if ((x = category_submenu_map.find (category)) != category_submenu_map.end()) { + submenu = x->second; + } else { + submenu = new Gtk::Menu; + by_category_items.push_back (MenuElem (category, *manage (submenu))); + category_submenu_map.insert (pair (category, 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_category; } void -PluginSelector::btn_add_clicked() +PluginSelector::plugin_chosen_from_menu (const PluginInfoPtr& pi) { - if (i_selected_plug) { - added_plugins.push_back (i_selected_plug); - o_selector.rescan(); + PluginPtr p = load_plugin (pi); + + if (p && interested_object) { + SelectedPlugins plugins; + plugins.push_back (p); + interested_object->use_plugins (plugins); } + + interested_object = 0; } void -PluginSelector::btn_remove_clicked() +PluginSelector::favorite_changed (const std::string& path) { - if (o_selected_plug > -1){ - gint row = 0; - list::iterator i = added_plugins.begin(); - while(row < o_selected_plug){ - i++; - row++; - } - added_plugins.erase(i); - o_selector.rescan(); - o_selected_plug = -1; + 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 */ + + (*iter)[plugin_columns.favorite] = favorite; + (*iter)[plugin_columns.hidden] = false; + 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); + + manager.save_statuses (); + + build_plugin_menu (); + } + in_row_change = false; } -// Adds a plugin, and closes the window. -void -PluginSelector::btn_ok_clicked() +void +PluginSelector::hidden_changed (const std::string& path) { - using namespace Gtk::CList_Helpers; + PluginInfoPtr pi; + + if (in_row_change) { + return; + } + + in_row_change = true; - list::iterator i; + TreeModel::iterator iter = plugin_model->get_iter (path); - for (i = added_plugins.begin(); i != added_plugins.end(); ++i){ - use_plugin (*i); + if (iter) { + + bool hidden = !(*iter)[plugin_columns.hidden]; + + /* change state */ + + (*iter)[plugin_columns.favorite] = false; + (*iter)[plugin_columns.hidden] = hidden; + 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); + + manager.save_statuses (); + + build_plugin_menu (); } + in_row_change = false; +} - hide(); - added_plugins.clear(); - o_selector.rescan(); - i_selected_plug = 0; - o_selected_plug = -1; +bool +PluginSelector::fil_hidden_button_release (GdkEventButton*) +{ + _show_hidden = (fil_hidden_button.active_state() == 0); + fil_hidden_button.set_active (_show_hidden); + refill (); + return false; +} - SelectionList s_list = ladspa_display.clist().selection(); - SelectionList::iterator s = s_list.begin(); - if (s != s_list.end()) { - (*s).unselect(); +static Gtkmm2ext::ActiveState next_state (Gtkmm2ext::ActiveState s){ + switch (s) { + case Gtkmm2ext::Off: + return Gtkmm2ext::ImplicitActive; + break; + case Gtkmm2ext::ImplicitActive: + return Gtkmm2ext::ExplicitActive; + break; + case Gtkmm2ext::ExplicitActive: + return Gtkmm2ext::Off; + break; + default: assert(0); break; // not reached } + /* impossible, but keep some compiles happy */ + fatal << string_compose (_("programming error: %1"), + X_("Illegal Active State.")) + << endmsg; + abort(); /*NOTREACHED*/ + return Gtkmm2ext::Off; +} -#ifdef VST_SUPPORT - SelectionList v_list = vst_display.clist().selection(); - SelectionList::iterator v = v_list.begin(); - if (v != v_list.end()) { - (*v).unselect(); +static Gtkmm2ext::ActiveState prev_state (Gtkmm2ext::ActiveState s){ + switch (s) { + case Gtkmm2ext::Off: + return Gtkmm2ext::ExplicitActive; + break; + case Gtkmm2ext::ImplicitActive: + return Gtkmm2ext::Off; + break; + case Gtkmm2ext::ExplicitActive: + return Gtkmm2ext::ImplicitActive; + break; + default: assert(0); break; // not reached } -#endif + /* impossible, but keep some compiles happy */ + fatal << string_compose (_("programming error: %1"), + X_("Illegal Active State.")) + << endmsg; + abort(); /*NOTREACHED*/ + return Gtkmm2ext::Off; } -void -PluginSelector::btn_cancel_clicked() +bool +PluginSelector::fil_instruments_button_release (GdkEventButton* ev) { - hide(); - added_plugins.clear(); - o_selector.rescan(); - i_selected_plug = 0; - o_selected_plug = -1; + if (ev->button == 3) { + _show_instruments = prev_state (fil_instruments_button.active_state()); + } else { + _show_instruments = next_state (fil_instruments_button.active_state()); + } + fil_instruments_button.set_active_state (_show_instruments); + refill (); + return false; } -void -PluginSelector::btn_update_clicked() +bool +PluginSelector::fil_analysis_button_release (GdkEventButton* ev) { - manager->refresh (); - ladspa_display.rescan (); + if (ev->button == 3) { + _show_analysers = prev_state (fil_analysis_button.active_state()); + } else { + _show_analysers = next_state (fil_analysis_button.active_state()); + } + fil_analysis_button.set_active_state (_show_analysers); + refill (); + return false; } -gint -PluginSelector::wm_close(GdkEventAny* ev) +bool +PluginSelector::fil_utils_button_release (GdkEventButton* ev) +{ + if (ev->button == 3) { + _show_utils = prev_state (fil_utils_button.active_state()); + } else { + _show_utils = next_state (fil_utils_button.active_state()); + } + fil_utils_button.set_active_state (_show_utils); + refill (); + return false; +} + +void +PluginSelector::show_manager () { - btn_cancel_clicked(); - return TRUE; + show_all(); + run (); } void -PluginSelector::column_clicked (int column, GtkCList* clist) +PluginSelector::set_interested_object (PluginInterestedObject& obj) { - gtk_clist_set_sort_column (clist, column); - gtk_clist_sort (clist); + interested_object = &obj; }