+
+void
+Mixer_UI::monitor_section_attached ()
+{
+ Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
+ Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
+ act->set_sensitive (true);
+ tact->set_active ();
+}
+
+void
+Mixer_UI::monitor_section_detached ()
+{
+ Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
+ act->set_sensitive (false);
+}
+
+void
+Mixer_UI::store_current_favorite_order ()
+{
+ typedef Gtk::TreeModel::Children type_children;
+ type_children children = favorite_plugins_model->children();
+ favorite_order.clear();
+ for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter)
+ {
+ Gtk::TreeModel::Row row = *iter;
+ ARDOUR::PluginPresetPtr ppp = row[favorite_plugins_columns.plugin];
+ favorite_order.push_back (ppp->_pip);
+ std::string name = row[favorite_plugins_columns.name];
+ favorite_ui_state[(*ppp->_pip).unique_id] = favorite_plugins_display.row_expanded (favorite_plugins_model->get_path(iter));
+ }
+}
+
+void
+Mixer_UI::save_favorite_ui_state (const TreeModel::iterator& iter, const TreeModel::Path& path)
+{
+ Gtk::TreeModel::Row row = *iter;
+ ARDOUR::PluginPresetPtr ppp = row[favorite_plugins_columns.plugin];
+ assert (ppp);
+ favorite_ui_state[(*ppp->_pip).unique_id] = favorite_plugins_display.row_expanded (favorite_plugins_model->get_path(iter));
+}
+
+void
+Mixer_UI::refiller (PluginInfoList& result, const PluginInfoList& plugs)
+{
+ PluginManager& manager (PluginManager::instance());
+ for (PluginInfoList::const_iterator i = plugs.begin(); i != plugs.end(); ++i) {
+ if (manager.get_status (*i) != PluginManager::Favorite) {
+ continue;
+ }
+ result.push_back (*i);
+ }
+}
+
+struct PluginCustomSorter {
+public:
+ bool operator() (PluginInfoPtr a, PluginInfoPtr b) const {
+ PluginInfoList::const_iterator aiter = _user.begin();
+ PluginInfoList::const_iterator biter = _user.begin();
+ while (aiter != _user.end()) { if ((*aiter)->unique_id == a->unique_id) { break; } ++aiter; }
+ while (biter != _user.end()) { if ((*biter)->unique_id == b->unique_id) { break; } ++biter; }
+
+ if (aiter != _user.end() && biter != _user.end()) {
+ return std::distance (_user.begin(), aiter) < std::distance (_user.begin(), biter);
+ }
+ if (aiter != _user.end()) {
+ return true;
+ }
+ if (biter != _user.end()) {
+ return false;
+ }
+ return ARDOUR::cmp_nocase((*a).name, (*b).name) == -1;
+ }
+ PluginCustomSorter(PluginInfoList user) : _user (user) {}
+private:
+ PluginInfoList _user;
+};
+
+void
+Mixer_UI::refill_favorite_plugins ()
+{
+ PluginInfoList plugs;
+ PluginManager& mgr (PluginManager::instance());
+
+#ifdef LV2_SUPPORT
+ refiller (plugs, mgr.lv2_plugin_info ());
+#endif
+#ifdef WINDOWS_VST_SUPPORT
+ refiller (plugs, mgr.windows_vst_plugin_info ());
+#endif
+#ifdef LXVST_SUPPORT
+ refiller (plugs, mgr.lxvst_plugin_info ());
+#endif
+#ifdef AUDIOUNIT_SUPPORT
+ refiller (plugs, mgr.au_plugin_info ());
+#endif
+ refiller (plugs, mgr.ladspa_plugin_info ());
+ refiller (plugs, mgr.lua_plugin_info ());
+
+ store_current_favorite_order ();
+
+ PluginCustomSorter cmp (favorite_order);
+ plugs.sort (cmp);
+
+ favorite_order = plugs;
+
+ sync_treeview_from_favorite_order ();
+}
+
+void
+Mixer_UI::sync_treeview_favorite_ui_state (const TreeModel::Path& path, const TreeModel::iterator&)
+{
+ TreeIter iter;
+ if (!(iter = favorite_plugins_model->get_iter (path))) {
+ return;
+ }
+ ARDOUR::PluginPresetPtr ppp = (*iter)[favorite_plugins_columns.plugin];
+ if (!ppp) {
+ return;
+ }
+ PluginInfoPtr pip = ppp->_pip;
+ if (favorite_ui_state.find (pip->unique_id) != favorite_ui_state.end ()) {
+ if (favorite_ui_state[pip->unique_id]) {
+ favorite_plugins_display.expand_row (path, true);
+ }
+ }
+}
+
+void
+Mixer_UI::sync_treeview_from_favorite_order ()
+{
+ favorite_plugins_model->clear ();
+ for (PluginInfoList::const_iterator i = favorite_order.begin(); i != favorite_order.end(); ++i) {
+ PluginInfoPtr pip = (*i);
+
+ TreeModel::Row newrow = *(favorite_plugins_model->append());
+ newrow[favorite_plugins_columns.name] = (*i)->name;
+ newrow[favorite_plugins_columns.plugin] = PluginPresetPtr (new PluginPreset(pip));
+ if (!_session) {
+ continue;
+ }
+
+ vector<ARDOUR::Plugin::PresetRecord> presets = (*i)->get_presets (true);
+ for (vector<ARDOUR::Plugin::PresetRecord>::const_iterator j = presets.begin(); j != presets.end(); ++j) {
+ Gtk::TreeModel::Row child_row = *(favorite_plugins_model->append (newrow.children()));
+ child_row[favorite_plugins_columns.name] = (*j).label;
+ child_row[favorite_plugins_columns.plugin] = PluginPresetPtr (new PluginPreset(pip, &(*j)));
+ }
+ if (favorite_ui_state.find (pip->unique_id) != favorite_ui_state.end ()) {
+ if (favorite_ui_state[pip->unique_id]) {
+ favorite_plugins_display.expand_row (favorite_plugins_model->get_path(newrow), true);
+ }
+ }
+ }
+}
+
+void
+Mixer_UI::popup_note_context_menu (GdkEventButton *ev)
+{
+ using namespace Gtk::Menu_Helpers;
+
+ Gtk::Menu* m = manage (new Menu);
+ MenuList& items = m->items ();
+
+ if (_selection.routes.empty()) {
+ items.push_back (MenuElem (_("No Track/Bus is selected.")));
+ } else {
+ items.push_back (MenuElem (_("Add at the top"),
+ sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddTop)));
+ items.push_back (MenuElem (_("Add Pre-Fader"),
+ sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddPreFader)));
+ items.push_back (MenuElem (_("Add Post-Fader"),
+ sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddPostFader)));
+ items.push_back (MenuElem (_("Add at the end"),
+ sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddBottom)));
+ }
+
+ items.push_back (SeparatorElem());
+
+ items.push_back (MenuElem (_("Remove from favorites"), sigc::mem_fun (*this, &Mixer_UI::remove_selected_from_favorites)));
+
+ ARDOUR::PluginPresetPtr ppp = selected_plugin();
+ if (ppp && ppp->_preset.valid && ppp->_preset.user) {
+ // we cannot currently delete AU presets
+ if (!ppp->_pip || ppp->_pip->type != AudioUnit) {
+ items.push_back (MenuElem (_("Delete Preset"), sigc::mem_fun (*this, &Mixer_UI::delete_selected_preset)));
+ }
+ }
+
+ m->popup (ev->button, ev->time);
+}
+
+bool
+Mixer_UI::plugin_row_button_press (GdkEventButton *ev)
+{
+ if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 3) ) {
+ TreeModel::Path path;
+ TreeViewColumn* column;
+ int cellx, celly;
+ if (favorite_plugins_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
+ Glib::RefPtr<Gtk::TreeView::Selection> selection = favorite_plugins_display.get_selection();
+ if (selection) {
+ selection->unselect_all();
+ selection->select(path);
+ }
+ }
+ ARDOUR::PluginPresetPtr ppp = selected_plugin();
+ if (ppp) {
+ popup_note_context_menu (ev);
+ }
+ }
+ return false;
+}
+
+
+PluginPresetPtr
+Mixer_UI::selected_plugin ()
+{
+ Glib::RefPtr<Gtk::TreeView::Selection> selection = favorite_plugins_display.get_selection();
+ if (!selection) {
+ return PluginPresetPtr();
+ }
+ Gtk::TreeModel::iterator iter = selection->get_selected();
+ if (!iter) {
+ return PluginPresetPtr();
+ }
+ return (*iter)[favorite_plugins_columns.plugin];
+}
+
+void
+Mixer_UI::add_selected_processor (ProcessorPosition pos)
+{
+ ARDOUR::PluginPresetPtr ppp = selected_plugin();
+ if (ppp) {
+ add_favorite_processor (ppp, pos);
+ }
+}
+
+void
+Mixer_UI::delete_selected_preset ()
+{
+ if (!_session) {
+ return;
+ }
+ ARDOUR::PluginPresetPtr ppp = selected_plugin();
+ if (!ppp || !ppp->_preset.valid || !ppp->_preset.user) {
+ return;
+ }
+ PluginPtr plugin = ppp->_pip->load (*_session);
+ plugin->get_presets();
+ plugin->remove_preset (ppp->_preset.label);
+}
+
+void
+Mixer_UI::remove_selected_from_favorites ()
+{
+ ARDOUR::PluginPresetPtr ppp = selected_plugin();
+ if (!ppp) {
+ return;
+ }
+ PluginManager::PluginStatusType status = PluginManager::Normal;
+ PluginManager& manager (PluginManager::instance());
+
+ manager.set_status (ppp->_pip->type, ppp->_pip->unique_id, status);
+ manager.save_statuses ();
+}
+
+void
+Mixer_UI::plugin_row_activated (const TreeModel::Path& path, TreeViewColumn* column)
+{
+ TreeIter iter;
+ if (!(iter = favorite_plugins_model->get_iter (path))) {
+ return;
+ }
+ ARDOUR::PluginPresetPtr ppp = (*iter)[favorite_plugins_columns.plugin];
+ add_favorite_processor (ppp, AddPreFader); // TODO: preference?!
+}
+
+void
+Mixer_UI::add_favorite_processor (ARDOUR::PluginPresetPtr ppp, ProcessorPosition pos)
+{
+ if (!_session || _selection.routes.empty()) {
+ return;
+ }
+
+ PluginInfoPtr pip = ppp->_pip;
+ for (RouteUISelection::iterator i = _selection.routes.begin(); i != _selection.routes.end(); ++i) {
+ boost::shared_ptr<ARDOUR::Route> rt = (*i)->route();
+ if (!rt) { continue; }
+
+ PluginPtr p = pip->load (*_session);
+ if (!p) { continue; }
+
+ if (ppp->_preset.valid) {
+ p->load_preset (ppp->_preset);
+ }
+
+ Route::ProcessorStreams err;
+ boost::shared_ptr<Processor> processor (new PluginInsert (*_session, p));
+
+ switch (pos) {
+ case AddTop:
+ rt->add_processor_by_index (processor, 0, &err, Config->get_new_plugins_active ());
+ break;
+ case AddPreFader:
+ rt->add_processor (processor, PreFader, &err, Config->get_new_plugins_active ());
+ break;
+ case AddPostFader:
+ {
+ int idx = 0;
+ int pos = 0;
+ for (;;++idx) {
+ boost::shared_ptr<Processor> np = rt->nth_processor (idx);
+ if (!np) {
+ break;
+ }
+ if (!np->display_to_user()) {
+ continue;
+ }
+ if (boost::dynamic_pointer_cast<Amp> (np) && // Fader, not Trim
+ boost::dynamic_pointer_cast<Amp> (np)->gain_control()->parameter().type() == GainAutomation) {
+ break;
+ }
+ ++pos;
+ }
+ rt->add_processor_by_index (processor, ++pos, &err, Config->get_new_plugins_active ());
+ }
+ break;
+ case AddBottom:
+ rt->add_processor_by_index (processor, -1, &err, Config->get_new_plugins_active ());
+ break;
+ }
+ }
+}
+
+bool
+PluginTreeStore::row_drop_possible_vfunc(const Gtk::TreeModel::Path& dest, const Gtk::SelectionData& data) const
+{
+ if (data.get_target() != "GTK_TREE_MODEL_ROW") {
+ return false;
+ }
+
+ // only allow to re-order top-level items
+ TreePath src;
+ if (TreePath::get_from_selection_data (data, src)) {
+ if (src.up() && src.up()) {
+ return false;
+ }
+ }
+
+ // don't allow to drop as child-rows.
+ Gtk::TreeModel::Path _dest = dest; // un const
+ const bool is_child = _dest.up (); // explicit bool for clang
+ if (!is_child || _dest.empty ()) {
+ return true;
+ }
+ return false;
+}
+
+void
+Mixer_UI::plugin_drop (const Glib::RefPtr<Gdk::DragContext>&, const Gtk::SelectionData& data)
+{
+ if (data.get_target() != "PluginPresetPtr") {
+ return;
+ }
+ if (data.get_length() != sizeof (PluginPresetPtr)) {
+ return;
+ }
+ const void *d = data.get_data();
+ const PluginPresetPtr ppp = *(static_cast<const PluginPresetPtr*> (d));
+
+ PluginManager::PluginStatusType status = PluginManager::Favorite;
+ PluginManager& manager (PluginManager::instance());
+
+ manager.set_status (ppp->_pip->type, ppp->_pip->unique_id, status);
+ manager.save_statuses ();
+}
+
+void
+Mixer_UI::do_vca_assign (boost::shared_ptr<VCA> vca)
+{
+ /* call protected MixerActor:: method */
+ vca_assign (vca);
+}
+
+void
+Mixer_UI::do_vca_unassign (boost::shared_ptr<VCA> vca)
+{
+ /* call protected MixerActor:: method */
+ vca_unassign (vca);
+}