2 Copyright (C) 2000-2004 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
26 #include <sigc++/bind.h>
28 #include <gtkmm/accelmap.h>
30 #include "pbd/convert.h"
31 #include "pbd/stacktrace.h"
32 #include "pbd/unwind.h"
34 #include <glibmm/threads.h>
36 #include <gtkmm2ext/gtk_ui.h>
37 #include <gtkmm2ext/keyboard.h>
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/tearoff.h>
40 #include <gtkmm2ext/window_title.h>
41 #include <gtkmm2ext/doi.h>
43 #include "ardour/amp.h"
44 #include "ardour/debug.h"
45 #include "ardour/midi_track.h"
46 #include "ardour/plugin_manager.h"
47 #include "ardour/route_group.h"
48 #include "ardour/route_sorters.h"
49 #include "ardour/session.h"
50 #include "ardour/vca.h"
51 #include "ardour/vca_manager.h"
55 #include "mixer_strip.h"
56 #include "monitor_section.h"
57 #include "plugin_selector.h"
58 #include "public_editor.h"
59 #include "ardour_ui.h"
62 #include "route_sorter.h"
64 #include "gui_thread.h"
65 #include "mixer_group_tabs.h"
67 #include "ui_config.h"
68 #include "vca_master_strip.h"
72 using namespace ARDOUR;
73 using namespace ARDOUR_UI_UTILS;
77 using namespace Gtkmm2ext;
83 Mixer_UI* Mixer_UI::_instance = 0;
89 _instance = new Mixer_UI;
96 : Tabbable (_content, _("Mixer"))
97 , no_track_list_redisplay (false)
98 , in_group_row_change (false)
100 , _monitor_section (0)
101 , _plugin_selector (0)
102 , _strip_width (UIConfiguration::instance().get_default_narrow_ms() ? Narrow : Wide)
103 , ignore_reorder (false)
104 , _in_group_rebuild_or_clear (false)
105 , _route_deletion_in_progress (false)
106 , _following_editor_selection (false)
108 , _show_mixer_list (true)
110 Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::sync_treeview_from_order_keys, this), gui_context());
112 /* bindings was already set in MixerActor constructor */
114 _content.set_data ("ardour-bindings", bindings);
116 scroller.set_can_default (true);
117 // set_default (scroller);
119 scroller_base.set_flags (Gtk::CAN_FOCUS);
120 scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
121 scroller_base.set_name ("MixerWindow");
122 scroller_base.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::strip_scroller_button_release));
124 /* set up drag-n-drop */
125 vector<TargetEntry> target_table;
126 target_table.push_back (TargetEntry ("PluginFavoritePtr"));
127 scroller_base.drag_dest_set (target_table);
128 scroller_base.signal_drag_data_received().connect (sigc::mem_fun(*this, &Mixer_UI::scroller_drag_data_received));
130 // add as last item of strip packer
131 strip_packer.pack_end (scroller_base, true, true);
133 _group_tabs = new MixerGroupTabs (this);
134 VBox* b = manage (new VBox);
135 b->pack_start (*_group_tabs, PACK_SHRINK);
136 b->pack_start (strip_packer);
140 scroller.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC);
142 setup_track_display ();
144 group_model = ListStore::create (group_columns);
145 group_display.set_model (group_model);
146 group_display.append_column (_("Group"), group_columns.text);
147 group_display.append_column (_("Show"), group_columns.visible);
148 group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
149 group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
150 group_display.get_column (0)->set_expand(true);
151 group_display.get_column (1)->set_expand(false);
152 group_display.set_name ("EditGroupList");
153 group_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
154 group_display.set_reorderable (true);
155 group_display.set_headers_visible (true);
156 group_display.set_rules_hint (true);
157 group_display.set_can_focus(false);
159 /* name is directly editable */
161 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
162 name_cell->property_editable() = true;
163 name_cell->signal_edited().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_name_edit));
165 /* use checkbox for the active column */
167 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(group_display.get_column_cell_renderer (1));
168 active_cell->property_activatable() = true;
169 active_cell->property_radio() = false;
171 group_model->signal_row_changed().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_change));
172 /* We use this to notice drag-and-drop reorders of the group list */
173 group_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_deleted));
174 group_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::group_display_button_press), false);
176 group_display_scroller.add (group_display);
177 group_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
179 HBox* route_group_display_button_box = manage (new HBox());
181 Button* route_group_add_button = manage (new Button ());
182 Button* route_group_remove_button = manage (new Button ());
186 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
188 route_group_add_button->add (*w);
190 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
192 route_group_remove_button->add (*w);
194 route_group_display_button_box->set_homogeneous (true);
196 route_group_add_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_route_group));
197 route_group_remove_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::remove_selected_route_group));
199 route_group_display_button_box->add (*route_group_add_button);
200 route_group_display_button_box->add (*route_group_remove_button);
202 group_display_vbox.pack_start (group_display_scroller, true, true);
203 group_display_vbox.pack_start (*route_group_display_button_box, false, false);
205 group_display_frame.set_name ("BaseFrame");
206 group_display_frame.set_shadow_type (Gtk::SHADOW_IN);
207 group_display_frame.add (group_display_vbox);
210 list<TargetEntry> target_list;
211 target_list.push_back (TargetEntry ("PluginPresetPtr"));
213 favorite_plugins_model = PluginTreeStore::create (favorite_plugins_columns);
214 favorite_plugins_display.set_model (favorite_plugins_model);
215 favorite_plugins_display.append_column (_("Favorite Plugins"), favorite_plugins_columns.name);
216 favorite_plugins_display.set_name ("EditGroupList");
217 favorite_plugins_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
218 favorite_plugins_display.set_reorderable (false);
219 favorite_plugins_display.set_headers_visible (true);
220 favorite_plugins_display.set_rules_hint (true);
221 favorite_plugins_display.set_can_focus (false);
222 favorite_plugins_display.add_object_drag (favorite_plugins_columns.plugin.index(), "PluginFavoritePtr");
223 favorite_plugins_display.set_drag_column (favorite_plugins_columns.name.index());
224 favorite_plugins_display.add_drop_targets (target_list);
225 favorite_plugins_display.signal_row_activated().connect (sigc::mem_fun (*this, &Mixer_UI::plugin_row_activated));
226 favorite_plugins_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::plugin_row_button_press), false);
227 favorite_plugins_display.signal_drop.connect (sigc::mem_fun (*this, &Mixer_UI::plugin_drop));
228 favorite_plugins_display.signal_row_expanded().connect (sigc::mem_fun (*this, &Mixer_UI::save_favorite_ui_state));
229 favorite_plugins_display.signal_row_collapsed().connect (sigc::mem_fun (*this, &Mixer_UI::save_favorite_ui_state));
230 favorite_plugins_model->signal_row_has_child_toggled().connect (sigc::mem_fun (*this, &Mixer_UI::sync_treeview_favorite_ui_state));
232 favorite_plugins_scroller.add (favorite_plugins_display);
233 favorite_plugins_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
235 favorite_plugins_frame.set_name ("BaseFrame");
236 favorite_plugins_frame.set_shadow_type (Gtk::SHADOW_IN);
237 favorite_plugins_frame.add (favorite_plugins_scroller);
239 rhs_pane1.pack1 (favorite_plugins_frame, false, true);
240 rhs_pane1.pack2 (track_display_frame);
241 rhs_pane2.pack1 (rhs_pane1);
242 rhs_pane2.pack2 (group_display_frame);
244 list_vpacker.pack_start (rhs_pane2, true, true);
246 vca_scroller.add (vca_packer);
247 vca_scroller.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC);
249 inner_pane.pack1 (scroller);
250 inner_pane.pack2 (vca_scroller);
252 global_hpacker.pack_start (inner_pane, true, true);
253 global_hpacker.pack_start (out_packer, false, false);
255 list_hpane.pack1(list_vpacker, false, true);
256 list_hpane.pack2(global_hpacker, true, false);
258 rhs_pane1.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
259 static_cast<Gtk::Paned*> (&rhs_pane1)));
260 rhs_pane2.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
261 static_cast<Gtk::Paned*> (&rhs_pane2)));
262 list_hpane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
263 static_cast<Gtk::Paned*> (&list_hpane)));
264 inner_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
265 static_cast<Gtk::Paned*> (&inner_pane)));
267 _content.pack_start (list_hpane, true, true);
271 route_group_display_button_box->show();
272 route_group_add_button->show();
273 route_group_remove_button->show();
276 _content.set_name ("MixerWindow");
278 global_hpacker.show();
280 scroller_base.show();
281 scroller_hpacker.show();
282 mixer_scroller_vpacker.show();
284 group_display_button_label.show();
285 group_display_button.show();
286 group_display_scroller.show();
287 favorite_plugins_scroller.show();
288 group_display_vbox.show();
289 group_display_frame.show();
290 favorite_plugins_frame.show();
299 group_display.show();
300 favorite_plugins_display.show();
302 MixerStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_strip, this, _1), gui_context());
304 #ifndef DEFER_PLUGIN_SELECTOR_LOAD
305 _plugin_selector = new PluginSelector (PluginManager::instance ());
307 #error implement deferred Plugin-Favorite list
309 PluginManager::instance ().PluginListChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context());
310 PluginManager::instance ().PluginStatusesChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context());
311 ARDOUR::Plugin::PresetsChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context());
314 Mixer_UI::~Mixer_UI ()
316 if (_monitor_section) {
317 monitor_section_detached ();
318 delete _monitor_section;
320 delete _plugin_selector;
324 Mixer_UI::track_editor_selection ()
326 PublicEditor::instance().get_selection().TracksChanged.connect (sigc::mem_fun (*this, &Mixer_UI::follow_editor_selection));
330 Mixer_UI::use_own_window (bool and_fill_it)
332 bool new_window = !own_window();
334 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
337 if (win && new_window) {
338 win->set_name ("MixerWindow");
339 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Mixer"), this);
340 win->signal_scroll_event().connect (sigc::mem_fun (*this, &Mixer_UI::on_scroll_event), false);
341 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
342 win->set_data ("ardour-bindings", bindings);
350 Mixer_UI::show_window ()
352 Tabbable::show_window ();
354 /* show/hide group tabs as required */
355 parameter_changed ("show-group-tabs");
357 /* now reset each strips width so the right widgets are shown */
360 TreeModel::Children rows = track_model->children();
361 TreeModel::Children::iterator ri;
363 for (ri = rows.begin(); ri != rows.end(); ++ri) {
364 ms = (*ri)[track_columns.strip];
368 ms->set_width_enum (ms->get_width_enum (), ms->width_owner());
369 /* Fix visibility of mixer strip stuff */
370 ms->parameter_changed (X_("mixer-element-visibility"));
373 /* force focus into main area */
374 scroller_base.grab_focus ();
378 Mixer_UI::add_masters (VCAList& vcas)
380 for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
382 VCAMasterStrip* vms = new VCAMasterStrip (_session, *v);
384 TreeModel::Row row = *(track_model->append());
385 row[track_columns.text] = (*v)->name();
386 row[track_columns.visible] = true;
387 row[track_columns.vca] = vms;
389 vms->CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_master, this, _1), gui_context());
392 redisplay_track_list ();
396 Mixer_UI::remove_master (VCAMasterStrip* vms)
398 if (_session && _session->deletion_in_progress()) {
399 /* its all being taken care of */
403 TreeModel::Children rows = track_model->children();
404 TreeModel::Children::iterator ri;
406 for (ri = rows.begin(); ri != rows.end(); ++ri) {
407 if ((*ri)[track_columns.vca] == vms) {
408 PBD::Unwinder<bool> uw (_route_deletion_in_progress, true);
409 track_model->erase (ri);
416 Mixer_UI::add_strips (RouteList& routes)
418 Gtk::TreeModel::Children::iterator insert_iter = track_model->children().end();
419 uint32_t nroutes = 0;
421 for (Gtk::TreeModel::Children::iterator it = track_model->children().begin(); it != track_model->children().end(); ++it) {
422 boost::shared_ptr<Route> r = (*it)[track_columns.route];
430 if (r->order_key() == (routes.front()->order_key() + routes.size())) {
437 _selection.clear_routes ();
443 no_track_list_redisplay = true;
444 track_display.set_model (Glib::RefPtr<ListStore>());
446 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
447 boost::shared_ptr<Route> route = (*x);
449 if (route->is_auditioner()) {
453 if (route->is_monitor()) {
455 if (!_monitor_section) {
456 _monitor_section = new MonitorSection (_session);
458 XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
460 _monitor_section->tearoff().set_state (*mnode);
464 out_packer.pack_end (_monitor_section->tearoff(), false, false);
465 _monitor_section->set_session (_session);
466 _monitor_section->tearoff().show_all ();
468 _monitor_section->tearoff().Detach.connect (sigc::mem_fun(*this, &Mixer_UI::monitor_section_detached));
469 _monitor_section->tearoff().Attach.connect (sigc::mem_fun(*this, &Mixer_UI::monitor_section_attached));
471 monitor_section_attached ();
473 route->DropReferences.connect (*this, invalidator(*this), boost::bind (&Mixer_UI::monitor_section_going_away, this), gui_context());
475 /* no regular strip shown for control out */
480 strip = new MixerStrip (*this, _session, route);
481 strips.push_back (strip);
483 UIConfiguration::instance().get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide;
485 if (strip->width_owner() != strip) {
486 strip->set_width_enum (_strip_width, this);
491 TreeModel::Row row = *(track_model->insert(insert_iter));
492 row[track_columns.text] = route->name();
493 row[track_columns.visible] = strip->route()->is_master() ? true : strip->marked_for_display();
494 row[track_columns.route] = route;
495 row[track_columns.strip] = strip;
496 row[track_columns.vca] = 0;
499 _selection.add (strip);
502 route->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::strip_property_changed, this, _1, strip), gui_context());
504 strip->WidthChanged.connect (sigc::mem_fun(*this, &Mixer_UI::strip_width_changed));
505 strip->signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::strip_button_release_event), strip));
508 } catch (const std::exception& e) {
509 error << string_compose (_("Error adding GUI elements for new tracks/busses %1"), e.what()) << endmsg;
512 no_track_list_redisplay = false;
513 track_display.set_model (track_model);
515 sync_order_keys_from_treeview ();
516 redisplay_track_list ();
520 Mixer_UI::deselect_all_strip_processors ()
522 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
523 (*i)->deselect_all_processors();
528 Mixer_UI::select_strip (MixerStrip& ms, bool add)
531 _selection.add (&ms);
533 _selection.set (&ms);
538 Mixer_UI::select_none ()
540 _selection.clear_routes();
541 deselect_all_strip_processors();
545 Mixer_UI::delete_processors ()
547 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
548 (*i)->delete_processors();
554 Mixer_UI::remove_strip (MixerStrip* strip)
556 if (_session && _session->deletion_in_progress()) {
557 /* its all being taken care of */
561 TreeModel::Children rows = track_model->children();
562 TreeModel::Children::iterator ri;
563 list<MixerStrip *>::iterator i;
565 if ((i = find (strips.begin(), strips.end(), strip)) != strips.end()) {
569 for (ri = rows.begin(); ri != rows.end(); ++ri) {
570 if ((*ri)[track_columns.strip] == strip) {
571 PBD::Unwinder<bool> uw (_route_deletion_in_progress, true);
572 track_model->erase (ri);
579 Mixer_UI::reset_remote_control_ids ()
581 if (Config->get_remote_model() == UserOrdered || !_session || _session->deletion_in_progress()) {
585 TreeModel::Children rows = track_model->children();
591 DEBUG_TRACE (DEBUG::OrderKeys, "mixer resets remote control ids after remote model change\n");
593 TreeModel::Children::iterator ri;
594 bool rid_change = false;
596 uint32_t invisible_key = UINT32_MAX;
598 for (ri = rows.begin(); ri != rows.end(); ++ri) {
600 /* skip two special values */
602 if (rid == Route::MasterBusRemoteControlID) {
606 if (rid == Route::MonitorBusRemoteControlID) {
610 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
611 bool visible = (*ri)[track_columns.visible];
617 if (!route->is_master() && !route->is_monitor()) {
619 uint32_t new_rid = (visible ? rid : invisible_key--);
621 if (new_rid != route->remote_control_id()) {
622 route->set_remote_control_id_explicit (new_rid);
633 /* tell the world that we changed the remote control IDs */
634 _session->notify_remote_id_change ();
639 Mixer_UI::sync_order_keys_from_treeview ()
641 if (ignore_reorder || !_session || _session->deletion_in_progress()) {
645 TreeModel::Children rows = track_model->children();
651 DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync order keys from model\n");
653 TreeModel::Children::iterator ri;
654 bool changed = false;
655 bool rid_change = false;
658 uint32_t invisible_key = UINT32_MAX;
660 for (ri = rows.begin(); ri != rows.end(); ++ri) {
661 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
662 bool visible = (*ri)[track_columns.visible];
668 uint32_t old_key = route->order_key ();
670 if (order != old_key) {
671 route->set_order_key (order);
675 if ((Config->get_remote_model() == MixerOrdered) && !route->is_master() && !route->is_monitor()) {
677 uint32_t new_rid = (visible ? rid : invisible_key--);
679 if (new_rid != route->remote_control_id()) {
680 route->set_remote_control_id_explicit (new_rid);
694 /* tell everyone that we changed the mixer sort keys */
695 _session->sync_order_keys ();
699 /* tell the world that we changed the remote control IDs */
700 _session->notify_remote_id_change ();
705 Mixer_UI::sync_treeview_from_order_keys ()
707 if (!_session || _session->deletion_in_progress()) {
711 DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync model from order keys.\n");
713 /* we could get here after either a change in the Mixer or Editor sort
714 * order, but either way, the mixer order keys reflect the intended
715 * order for the GUI, so reorder the treeview model to match it.
718 vector<int> neworder;
719 TreeModel::Children rows = track_model->children();
720 uint32_t old_order = 0;
721 bool changed = false;
728 uint32_t vca_cnt = 0;
729 uint32_t max_route_order_key = 0;
731 /* count number of Routes in track_model (there may be some odd reason
732 why this is not the same as the number in the session, but here we
733 care about the track model.
736 for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri) {
737 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
739 max_route_order_key = max (route->order_key(), max_route_order_key);
743 for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
744 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
746 /* VCAs need to sort after all routes. We don't display
747 * them in the same place (March 2016), but we don't
748 * want them intermixed in the track_model
750 sorted.push_back (OrderKeys (old_order, max_route_order_key + ++vca_cnt));
752 sorted.push_back (OrderKeys (old_order, route->order_key ()));
756 SortByNewDisplayOrder cmp;
758 sort (sorted.begin(), sorted.end(), cmp);
759 neworder.assign (sorted.size(), 0);
763 for (OrderingKeys::iterator sr = sorted.begin(); sr != sorted.end(); ++sr, ++n) {
765 neworder[n] = sr->old_display_order;
767 if (sr->old_display_order != n) {
771 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("MIXER change order from %1 to %2\n",
772 sr->old_display_order, n));
776 Unwinder<bool> uw (ignore_reorder, true);
777 track_model->reorder (neworder);
780 redisplay_track_list ();
784 Mixer_UI::follow_editor_selection ()
786 if (_following_editor_selection) {
790 _following_editor_selection = true;
791 _selection.block_routes_changed (true);
793 TrackSelection& s (PublicEditor::instance().get_selection().tracks);
795 _selection.clear_routes ();
797 for (TrackViewList::iterator i = s.begin(); i != s.end(); ++i) {
798 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*i);
800 MixerStrip* ms = strip_by_route (rtav->route());
807 _following_editor_selection = false;
808 _selection.block_routes_changed (false);
813 Mixer_UI::strip_by_route (boost::shared_ptr<Route> r)
815 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
816 if ((*i)->route() == r) {
825 Mixer_UI::strip_button_release_event (GdkEventButton *ev, MixerStrip *strip)
827 if (ev->button == 1) {
828 if (_selection.selected (strip)) {
829 /* primary-click: toggle selection state of strip */
830 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
831 _selection.remove (strip);
832 } else if (_selection.routes.size() > 1) {
833 /* de-select others */
834 _selection.set (strip);
837 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
838 _selection.add (strip);
839 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::RangeSelectModifier)) {
841 if (!_selection.selected(strip)) {
843 /* extend selection */
845 vector<MixerStrip*> tmp;
846 bool accumulate = false;
847 bool found_another = false;
849 tmp.push_back (strip);
851 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
853 /* hit clicked strip, start accumulating till we hit the first
862 } else if (_selection.selected (*i)) {
863 /* hit selected strip. if currently accumulating others,
864 we're done. if not accumulating others, start doing so.
866 found_another = true;
881 for (vector<MixerStrip*>::iterator i = tmp.begin(); i != tmp.end(); ++i) {
885 _selection.set (strip); //user wants to start a range selection, but there aren't any others selected yet
889 _selection.set (strip);
898 Mixer_UI::set_session (Session* sess)
900 SessionHandlePtr::set_session (sess);
902 if (_plugin_selector) {
903 _plugin_selector->set_session (_session);
906 _group_tabs->set_session (sess);
912 refill_favorite_plugins();
914 XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
915 set_state (*node, 0);
919 initial_track_display ();
921 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_strips, this, _1), gui_context());
922 _session->route_group_added.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_route_group, this, _1), gui_context());
923 _session->route_group_removed.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
924 _session->route_groups_reordered.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
925 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::parameter_changed, this, _1), gui_context());
926 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::update_title, this), gui_context());
927 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::update_title, this), gui_context());
929 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_masters, this, _1), gui_context());
931 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::parameter_changed, this, _1), gui_context ());
933 route_groups_changed ();
942 Mixer_UI::session_going_away ()
944 ENSURE_GUI_THREAD (*this, &Mixer_UI::session_going_away);
946 _in_group_rebuild_or_clear = true;
947 group_model->clear ();
948 _in_group_rebuild_or_clear = false;
951 track_model->clear ();
953 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
957 if (_monitor_section) {
958 _monitor_section->tearoff().hide_visible ();
961 monitor_section_detached ();
967 SessionHandlePtr::session_going_away ();
974 Mixer_UI::track_visibility_changed (std::string const & path)
976 if (_session && _session->deletion_in_progress()) {
982 if ((iter = track_model->get_iter (path))) {
983 MixerStrip* strip = (*iter)[track_columns.strip];
985 bool visible = (*iter)[track_columns.visible];
987 if (strip->set_marked_for_display (!visible)) {
988 update_track_visibility ();
995 Mixer_UI::update_track_visibility ()
997 TreeModel::Children rows = track_model->children();
998 TreeModel::Children::iterator i;
1001 Unwinder<bool> uw (no_track_list_redisplay, true);
1003 for (i = rows.begin(); i != rows.end(); ++i) {
1004 MixerStrip *strip = (*i)[track_columns.strip];
1006 (*i)[track_columns.visible] = strip->marked_for_display ();
1010 /* force route order keys catch up with visibility changes
1013 sync_order_keys_from_treeview ();
1016 redisplay_track_list ();
1020 Mixer_UI::show_strip (MixerStrip* ms)
1022 TreeModel::Children rows = track_model->children();
1023 TreeModel::Children::iterator i;
1025 for (i = rows.begin(); i != rows.end(); ++i) {
1027 MixerStrip* strip = (*i)[track_columns.strip];
1029 (*i)[track_columns.visible] = true;
1030 redisplay_track_list ();
1037 Mixer_UI::hide_strip (MixerStrip* ms)
1039 TreeModel::Children rows = track_model->children();
1040 TreeModel::Children::iterator i;
1042 for (i = rows.begin(); i != rows.end(); ++i) {
1044 MixerStrip* strip = (*i)[track_columns.strip];
1046 (*i)[track_columns.visible] = false;
1047 redisplay_track_list ();
1054 Mixer_UI::start_updating ()
1056 fast_screen_update_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &Mixer_UI::fast_update_strips));
1061 Mixer_UI::stop_updating ()
1063 fast_screen_update_connection.disconnect();
1068 Mixer_UI::fast_update_strips ()
1070 if (_content.is_mapped () && _session) {
1071 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1072 (*i)->fast_update ();
1078 Mixer_UI::set_all_strips_visibility (bool yn)
1080 TreeModel::Children rows = track_model->children();
1081 TreeModel::Children::iterator i;
1084 Unwinder<bool> uw (no_track_list_redisplay, true);
1086 for (i = rows.begin(); i != rows.end(); ++i) {
1088 TreeModel::Row row = (*i);
1089 MixerStrip* strip = row[track_columns.strip];
1095 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1099 (*i)[track_columns.visible] = yn;
1103 redisplay_track_list ();
1108 Mixer_UI::set_all_audio_midi_visibility (int tracks, bool yn)
1110 TreeModel::Children rows = track_model->children();
1111 TreeModel::Children::iterator i;
1114 Unwinder<bool> uw (no_track_list_redisplay, true);
1116 for (i = rows.begin(); i != rows.end(); ++i) {
1117 TreeModel::Row row = (*i);
1118 MixerStrip* strip = row[track_columns.strip];
1124 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1128 boost::shared_ptr<AudioTrack> at = strip->audio_track();
1129 boost::shared_ptr<MidiTrack> mt = strip->midi_track();
1133 (*i)[track_columns.visible] = yn;
1137 if (at) { /* track */
1138 (*i)[track_columns.visible] = yn;
1143 if (!at && !mt) { /* bus */
1144 (*i)[track_columns.visible] = yn;
1149 if (mt) { /* midi-track */
1150 (*i)[track_columns.visible] = yn;
1157 redisplay_track_list ();
1161 Mixer_UI::hide_all_routes ()
1163 set_all_strips_visibility (false);
1167 Mixer_UI::show_all_routes ()
1169 set_all_strips_visibility (true);
1173 Mixer_UI::show_all_audiobus ()
1175 set_all_audio_midi_visibility (2, true);
1178 Mixer_UI::hide_all_audiobus ()
1180 set_all_audio_midi_visibility (2, false);
1184 Mixer_UI::show_all_audiotracks()
1186 set_all_audio_midi_visibility (1, true);
1189 Mixer_UI::hide_all_audiotracks ()
1191 set_all_audio_midi_visibility (1, false);
1195 Mixer_UI::show_all_miditracks()
1197 set_all_audio_midi_visibility (3, true);
1200 Mixer_UI::hide_all_miditracks ()
1202 set_all_audio_midi_visibility (3, false);
1207 Mixer_UI::track_list_reorder (const TreeModel::Path&, const TreeModel::iterator&, int* /*new_order*/)
1209 DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview reordered\n");
1210 sync_order_keys_from_treeview ();
1214 Mixer_UI::track_list_delete (const Gtk::TreeModel::Path&)
1216 /* this happens as the second step of a DnD within the treeview as well
1217 as when a row/route is actually deleted.
1219 if it was a deletion then we have to force a redisplay because
1220 order keys may not have changed.
1223 DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview row deleted\n");
1224 sync_order_keys_from_treeview ();
1226 if (_route_deletion_in_progress) {
1227 redisplay_track_list ();
1232 Mixer_UI::redisplay_track_list ()
1234 TreeModel::Children rows = track_model->children();
1235 TreeModel::Children::iterator i;
1236 uint32_t n_masters = 0;
1238 if (no_track_list_redisplay) {
1242 container_clear (vca_packer);
1244 for (i = rows.begin(); i != rows.end(); ++i) {
1246 VCAMasterStrip* vms = (*i)[track_columns.vca];
1249 vca_packer.pack_start (*vms, false, false);
1255 MixerStrip* strip = (*i)[track_columns.strip];
1258 /* we're in the middle of changing a row, don't worry */
1262 bool const visible = (*i)[track_columns.visible];
1265 strip->set_gui_property ("visible", true);
1267 if (strip->packed()) {
1269 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1270 out_packer.reorder_child (*strip, -1);
1273 strip_packer.reorder_child (*strip, -1); /* put at end */
1278 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1279 out_packer.pack_start (*strip, false, false);
1281 strip_packer.pack_start (*strip, false, false);
1283 strip->set_packed (true);
1288 strip->set_gui_property ("visible", false);
1290 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1291 /* do nothing, these cannot be hidden */
1293 if (strip->packed()) {
1294 strip_packer.remove (*strip);
1295 strip->set_packed (false);
1301 /* update visibility of VCA assign buttons */
1303 if (n_masters == 0) {
1304 UIConfiguration::instance().set_mixer_strip_visibility (VisibilityGroup::remove_element (UIConfiguration::instance().get_mixer_strip_visibility(), X_("VCA")));
1306 UIConfiguration::instance().set_mixer_strip_visibility (VisibilityGroup::add_element (UIConfiguration::instance().get_mixer_strip_visibility(), X_("VCA")));
1309 _group_tabs->set_dirty ();
1313 Mixer_UI::strip_width_changed ()
1315 _group_tabs->set_dirty ();
1318 TreeModel::Children rows = track_model->children();
1319 TreeModel::Children::iterator i;
1322 for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
1323 MixerStrip* strip = (*i)[track_columns.strip];
1329 bool visible = (*i)[track_columns.visible];
1332 strip->queue_draw();
1340 Mixer_UI::initial_track_display ()
1342 boost::shared_ptr<RouteList> routes = _session->get_routes();
1343 RouteList copy (*routes);
1344 ARDOUR::SignalOrderRouteSorter sorter;
1349 Unwinder<bool> uw1 (no_track_list_redisplay, true);
1350 Unwinder<bool> uw2 (ignore_reorder, true);
1352 track_model->clear ();
1353 VCAList vcas = _session->vca_manager().vcas();
1358 _session->sync_order_keys ();
1360 redisplay_track_list ();
1364 Mixer_UI::show_track_list_menu ()
1366 if (track_menu == 0) {
1367 build_track_menu ();
1370 track_menu->popup (1, gtk_get_current_event_time());
1374 Mixer_UI::track_display_button_press (GdkEventButton* ev)
1376 if (Keyboard::is_context_menu_event (ev)) {
1377 show_track_list_menu ();
1385 Mixer_UI::build_track_menu ()
1387 using namespace Menu_Helpers;
1388 using namespace Gtk;
1390 track_menu = new Menu;
1391 track_menu->set_name ("ArdourContextMenu");
1392 MenuList& items = track_menu->items();
1394 items.push_back (MenuElem (_("Show All"), sigc::mem_fun(*this, &Mixer_UI::show_all_routes)));
1395 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun(*this, &Mixer_UI::hide_all_routes)));
1396 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
1397 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
1398 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus)));
1399 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
1400 items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &Mixer_UI::show_all_miditracks)));
1401 items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &Mixer_UI::hide_all_miditracks)));
1406 Mixer_UI::strip_property_changed (const PropertyChange& what_changed, MixerStrip* mx)
1408 if (!what_changed.contains (ARDOUR::Properties::name)) {
1412 ENSURE_GUI_THREAD (*this, &Mixer_UI::strip_name_changed, what_changed, mx)
1414 TreeModel::Children rows = track_model->children();
1415 TreeModel::Children::iterator i;
1417 for (i = rows.begin(); i != rows.end(); ++i) {
1418 if ((*i)[track_columns.strip] == mx) {
1419 (*i)[track_columns.text] = mx->route()->name();
1424 error << _("track display list item for renamed strip not found!") << endmsg;
1428 Mixer_UI::group_display_button_press (GdkEventButton* ev)
1430 TreeModel::Path path;
1431 TreeViewColumn* column;
1435 if (!group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
1436 _group_tabs->get_menu(0)->popup (1, ev->time);
1440 TreeIter iter = group_model->get_iter (path);
1442 _group_tabs->get_menu(0)->popup (1, ev->time);
1446 RouteGroup* group = (*iter)[group_columns.group];
1448 if (Keyboard::is_context_menu_event (ev)) {
1449 _group_tabs->get_menu(group)->popup (1, ev->time);
1453 switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
1455 if (Keyboard::is_edit_event (ev)) {
1457 // edit_route_group (group);
1459 group_display.queue_draw();
1468 bool visible = (*iter)[group_columns.visible];
1469 (*iter)[group_columns.visible] = !visible;
1471 group_display.queue_draw();
1484 Mixer_UI::activate_all_route_groups ()
1486 _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), true));
1490 Mixer_UI::disable_all_route_groups ()
1492 _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), false));
1496 Mixer_UI::route_groups_changed ()
1498 ENSURE_GUI_THREAD (*this, &Mixer_UI::route_groups_changed);
1500 _in_group_rebuild_or_clear = true;
1502 /* just rebuild the while thing */
1504 group_model->clear ();
1507 /* this is currently not used,
1508 * Mixer_UI::group_display_button_press() has a case for it,
1509 * and a commented edit_route_group() but that's n/a since 2011.
1511 * This code is left as reminder that
1512 * row[group_columns.group] = 0 has special meaning.
1516 row = *(group_model->append());
1517 row[group_columns.visible] = true;
1518 row[group_columns.text] = (_("-all-"));
1519 row[group_columns.group] = 0;
1523 _session->foreach_route_group (sigc::mem_fun (*this, &Mixer_UI::add_route_group));
1525 _group_tabs->set_dirty ();
1526 _in_group_rebuild_or_clear = false;
1530 Mixer_UI::new_route_group ()
1534 _group_tabs->run_new_group_dialog (rl);
1538 Mixer_UI::remove_selected_route_group ()
1540 Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1541 TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1547 TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1550 /* selection mode is single, so rows.begin() is it */
1552 if ((iter = group_model->get_iter (*i))) {
1554 RouteGroup* rg = (*iter)[group_columns.group];
1557 _session->remove_route_group (*rg);
1563 Mixer_UI::route_group_property_changed (RouteGroup* group, const PropertyChange& change)
1565 if (in_group_row_change) {
1569 /* force an update of any mixer strips that are using this group,
1570 otherwise mix group names don't change in mixer strips
1573 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1574 if ((*i)->route_group() == group) {
1575 (*i)->route_group_changed();
1579 TreeModel::iterator i;
1580 TreeModel::Children rows = group_model->children();
1581 Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1583 in_group_row_change = true;
1585 for (i = rows.begin(); i != rows.end(); ++i) {
1586 if ((*i)[group_columns.group] == group) {
1587 (*i)[group_columns.visible] = !group->is_hidden ();
1588 (*i)[group_columns.text] = group->name ();
1593 in_group_row_change = false;
1595 if (change.contains (Properties::name)) {
1596 _group_tabs->set_dirty ();
1599 for (list<MixerStrip*>::iterator j = strips.begin(); j != strips.end(); ++j) {
1600 if ((*j)->route_group() == group) {
1601 if (group->is_hidden ()) {
1611 Mixer_UI::show_mixer_list (bool yn)
1614 list_vpacker.show ();
1616 //if user wants to show the pane, we should make sure that it is wide enough to be visible
1617 int width = list_hpane.get_position();
1619 list_hpane.set_position(40);
1622 list_vpacker.hide ();
1625 _show_mixer_list = yn;
1629 Mixer_UI::show_monitor_section (bool yn)
1631 if (!monitor_section()) {
1634 if (monitor_section()->tearoff().torn_off()) {
1639 monitor_section()->tearoff().show();
1641 monitor_section()->tearoff().hide();
1646 Mixer_UI::route_group_name_edit (const std::string& path, const std::string& new_text)
1651 if ((iter = group_model->get_iter (path))) {
1653 if ((group = (*iter)[group_columns.group]) == 0) {
1657 if (new_text != group->name()) {
1658 group->set_name (new_text);
1664 Mixer_UI::route_group_row_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator& iter)
1668 if (in_group_row_change) {
1672 if ((group = (*iter)[group_columns.group]) == 0) {
1676 std::string name = (*iter)[group_columns.text];
1678 if (name != group->name()) {
1679 group->set_name (name);
1682 bool hidden = !(*iter)[group_columns.visible];
1684 if (hidden != group->is_hidden ()) {
1685 group->set_hidden (hidden, this);
1689 /** Called when a group model row is deleted, but also when the model is
1690 * reordered by a user drag-and-drop; the latter is what we are
1691 * interested in here.
1694 Mixer_UI::route_group_row_deleted (Gtk::TreeModel::Path const &)
1696 if (_in_group_rebuild_or_clear) {
1700 /* Re-write the session's route group list so that the new order is preserved */
1702 list<RouteGroup*> new_list;
1704 Gtk::TreeModel::Children children = group_model->children();
1705 for (Gtk::TreeModel::Children::iterator i = children.begin(); i != children.end(); ++i) {
1706 RouteGroup* g = (*i)[group_columns.group];
1708 new_list.push_back (g);
1712 _session->reorder_route_groups (new_list);
1717 Mixer_UI::add_route_group (RouteGroup* group)
1719 ENSURE_GUI_THREAD (*this, &Mixer_UI::add_route_group, group)
1722 in_group_row_change = true;
1724 TreeModel::Row row = *(group_model->append());
1725 row[group_columns.visible] = !group->is_hidden ();
1726 row[group_columns.group] = group;
1727 if (!group->name().empty()) {
1728 row[group_columns.text] = group->name();
1730 row[group_columns.text] = _("unnamed");
1734 group->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::route_group_property_changed, this, group, _1), gui_context());
1737 TreeViewColumn* col = group_display.get_column (0);
1738 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
1739 group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true);
1742 _group_tabs->set_dirty ();
1744 in_group_row_change = false;
1748 Mixer_UI::strip_scroller_button_release (GdkEventButton* ev)
1750 using namespace Menu_Helpers;
1752 if (Keyboard::is_context_menu_event (ev)) {
1753 ARDOUR_UI::instance()->add_route ();
1761 Mixer_UI::scroller_drag_data_received (const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, const Gtk::SelectionData& data, guint info, guint time)
1763 printf ("Mixer_UI::scroller_drag_data_received\n");
1764 if (data.get_target() != "PluginFavoritePtr") {
1765 context->drag_finish (false, false, time);
1769 const void * d = data.get_data();
1770 const Gtkmm2ext::DnDTreeView<ARDOUR::PluginPresetPtr>* tv = reinterpret_cast<const Gtkmm2ext::DnDTreeView<ARDOUR::PluginPresetPtr>*>(d);
1772 PluginPresetList nfos;
1774 tv->get_object_drag_data (nfos, &source);
1776 Route::ProcessorList pl;
1779 for (list<PluginPresetPtr>::const_iterator i = nfos.begin(); i != nfos.end(); ++i) {
1780 PluginPresetPtr ppp = (*i);
1781 PluginInfoPtr pip = ppp->_pip;
1782 if (!pip->is_instrument ()) {
1785 ARDOUR_UI::instance()->session_add_midi_track (NULL, 1, _("MIDI"), Config->get_strict_io (), pip, ppp->_preset.valid ? &ppp->_preset : 0);
1789 context->drag_finish (ok, false, time);
1793 Mixer_UI::set_strip_width (Width w, bool save)
1797 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1798 (*i)->set_width_enum (w, save ? (*i)->width_owner() : this);
1803 struct PluginStateSorter {
1805 bool operator() (PluginInfoPtr a, PluginInfoPtr b) const {
1806 std::list<std::string>::const_iterator aiter = std::find(_user.begin(), _user.end(), (*a).unique_id);
1807 std::list<std::string>::const_iterator biter = std::find(_user.begin(), _user.end(), (*b).unique_id);
1808 if (aiter != _user.end() && biter != _user.end()) {
1809 return std::distance (_user.begin(), aiter) < std::distance (_user.begin(), biter);
1811 if (aiter != _user.end()) {
1814 if (biter != _user.end()) {
1817 return ARDOUR::cmp_nocase((*a).name, (*b).name) == -1;
1820 PluginStateSorter(std::list<std::string> user) : _user (user) {}
1822 std::list<std::string> _user;
1826 Mixer_UI::set_state (const XMLNode& node, int version)
1828 XMLProperty const * prop;
1830 Tabbable::set_state (node, version);
1832 if ((prop = node.property ("narrow-strips"))) {
1833 if (string_is_affirmative (prop->value())) {
1834 set_strip_width (Narrow);
1836 set_strip_width (Wide);
1840 if ((prop = node.property ("show-mixer"))) {
1841 if (string_is_affirmative (prop->value())) {
1846 if ((prop = node.property ("maximised"))) {
1847 bool yn = string_is_affirmative (prop->value());
1848 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalMixer"));
1850 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1851 bool fs = tact && tact->get_active();
1853 ActionManager::do_action ("Common", "ToggleMaximalMixer");
1857 if ((prop = node.property ("show-mixer-list"))) {
1858 bool yn = string_is_affirmative (prop->value());
1859 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMixerList"));
1861 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1863 /* do it twice to force the change */
1864 tact->set_active (!yn);
1865 tact->set_active (yn);
1869 XMLNode* plugin_order;
1870 if ((plugin_order = find_named_node (node, "PluginOrder")) != 0) {
1871 store_current_favorite_order ();
1872 std::list<string> order;
1873 const XMLNodeList& kids = plugin_order->children("PluginInfo");
1874 XMLNodeConstIterator i;
1875 for (i = kids.begin(); i != kids.end(); ++i) {
1876 if ((prop = (*i)->property ("unique-id"))) {
1877 std::string unique_id = prop->value();
1878 order.push_back (unique_id);
1879 if ((prop = (*i)->property ("expanded"))) {
1880 favorite_ui_state[unique_id] = string_is_affirmative (prop->value());
1884 PluginStateSorter cmp (order);
1885 favorite_order.sort (cmp);
1886 sync_treeview_from_favorite_order ();
1892 Mixer_UI::get_state ()
1894 XMLNode* node = new XMLNode (X_("Mixer"));
1897 node->add_child_nocopy (Tabbable::get_state());
1899 snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (rhs_pane1, true));
1900 node->add_property(X_("mixer-rhs-pane1-pos"), string(buf));
1901 snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (rhs_pane2, true));
1902 node->add_property(X_("mixer-rhs_pane2-pos"), string(buf));
1903 snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (list_hpane, false));
1904 node->add_property(X_("mixer-list-hpane-pos"), string(buf));
1905 snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (inner_pane, false));
1906 node->add_property(X_("mixer-inner-pane-pos"), string(buf));
1908 node->add_property ("narrow-strips", _strip_width == Narrow ? "yes" : "no");
1909 node->add_property ("show-mixer", _visible ? "yes" : "no");
1910 node->add_property ("show-mixer-list", _show_mixer_list ? "yes" : "no");
1911 node->add_property ("maximised", _maximised ? "yes" : "no");
1913 store_current_favorite_order ();
1914 XMLNode* plugin_order = new XMLNode ("PluginOrder");
1916 for (PluginInfoList::const_iterator i = favorite_order.begin(); i != favorite_order.end(); ++i, ++cnt) {
1917 XMLNode* p = new XMLNode ("PluginInfo");
1918 p->add_property ("sort", cnt);
1919 p->add_property ("unique-id", (*i)->unique_id);
1920 if (favorite_ui_state.find ((*i)->unique_id) != favorite_ui_state.end ()) {
1921 p->add_property ("expanded", favorite_ui_state[(*i)->unique_id]);
1923 plugin_order->add_child_nocopy (*p);
1925 node->add_child_nocopy (*plugin_order);
1931 Mixer_UI::pane_allocation_handler (Allocation& allocation, Gtk::Paned* which)
1934 XMLProperty* prop = 0;
1935 XMLNode* geometry = ARDOUR_UI::instance()->mixer_settings();
1936 int height = default_height;
1937 static bool done[4] = { false, false, false, false };
1939 /* Gtk::Paned behaves very oddly and rather undesirably. Setting the
1940 * position is a crapshoot if you time it incorrectly with the overall
1941 * sizing of the Paned. For example, if you might retrieve the size with
1942 * ::get_position() and then later call ::set_position() on a Paned at
1943 * a time when its allocation is different than it was when you retrieved
1944 * the position. The position will be interpreted as the size of the
1945 * first (top or left) child widget. If packing/size allocation later
1946 * resizes the Paned to a (final) smaller size, the position will be
1947 * used in ways that mean that the Paned ends up NOT in the same state
1948 * that it was in when you originally saved the position.
1950 * Concrete example: Paned is 800 pixels wide, position is 400
1951 * (halfway). Save position as 400. During program restart, set
1952 * position to 400, before Paned has been allocated any space. Paned
1953 * ends up initially sized to 1200 pixels. Position is now 1/3 of the
1954 * way across/down. Subsequent resizes will leave the position 1/3 of
1955 * the way across, rather than leaving it as a fixed pixel
1956 * position. Eventually, the Paned ends up 800 pixels wide/high again,
1957 * but the position is now 267, not 400.
1961 * We deal with this by using two strategies:
1963 * 1) only set the position if the allocated size of the Paned is at
1964 * least as big as it needs to be for the position to make sense.
1966 * 2) in recent versions of Ardour, save the position as a fraction,
1967 * and restore it using that fraction.
1969 * So, we will only call ::set_position() AFTER the Paned is of a
1970 * sensible size, and then in addition, we will set the position in a
1971 * way that will be maintained as/when/if the Paned is resized.
1973 * Once we've called ::set_position() on a Paned, we don't do it
1977 if (which == static_cast<Gtk::Paned*> (&rhs_pane1)) {
1983 if (!geometry || (prop = geometry->property("mixer-rhs-pane1-pos")) == 0) {
1986 pos = atof (prop->value());
1990 /* older versions of Ardour stored absolute position */
1991 if ((done[0] = (allocation.get_height() > pos))) {
1992 rhs_pane1.set_position (pos);
1995 if ((done[0] = (allocation.get_height() > 1.0/pos))) {
1996 paned_set_position_as_fraction (rhs_pane1, pos, true);
2001 if (which == static_cast<Gtk::Paned*> (&rhs_pane2)) {
2007 if (!geometry || (prop = geometry->property("mixer-rhs-pane2-pos")) == 0) {
2008 pos = 2 * height / 3;
2010 pos = atof (prop->value());
2014 /* older versions of Ardour stored absolute position */
2015 if ((done[1] = (allocation.get_height() > pos))) {
2016 rhs_pane2.set_position (pos);
2019 if ((done[1] = (allocation.get_height() > 1.0/pos))) {
2020 paned_set_position_as_fraction (rhs_pane2, pos, true);
2025 if (which == static_cast<Gtk::Paned*> (&list_hpane)) {
2031 if (!geometry || (prop = geometry->property("mixer-list-hpane-pos")) == 0) {
2032 pos = std::max ((float)100, rintf ((float) 125 * UIConfiguration::instance().get_ui_scale()));
2034 pos = max (0.1, atof (prop->value ()));
2038 if ((done[2] = (allocation.get_width() > pos))) {
2039 list_hpane.set_position (pos);
2042 if ((done[2] = (allocation.get_width() > 1.0/pos))) {
2043 paned_set_position_as_fraction (list_hpane, pos, false);
2048 if (which == static_cast<Gtk::Paned*> (&inner_pane)) {
2054 if (!geometry || (prop = geometry->property("mixer-inner-pane-pos")) == 0) {
2055 pos = std::max ((float)100, rintf ((float) 125 * UIConfiguration::instance().get_ui_scale()));
2057 pos = max (0.1, atof (prop->value ()));
2061 /* older versions of Ardour stored absolute position */
2062 if ((done[3] = (allocation.get_width() > pos))) {
2063 inner_pane.set_position (pos);
2066 if ((done[3] = (allocation.get_width() > 1.0/pos))) {
2067 paned_set_position_as_fraction (inner_pane, pos, false);
2074 Mixer_UI::scroll_left ()
2076 if (!scroller.get_hscrollbar()) return;
2077 Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
2078 /* stupid GTK: can't rely on clamping across versions */
2079 scroller.get_hscrollbar()->set_value (max (adj->get_lower(), adj->get_value() - adj->get_step_increment()));
2083 Mixer_UI::scroll_right ()
2085 if (!scroller.get_hscrollbar()) return;
2086 Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
2087 /* stupid GTK: can't rely on clamping across versions */
2088 scroller.get_hscrollbar()->set_value (min (adj->get_upper(), adj->get_value() + adj->get_step_increment()));
2092 Mixer_UI::on_scroll_event (GdkEventScroll* ev)
2094 switch (ev->direction) {
2095 case GDK_SCROLL_LEFT:
2099 if (ev->state & Keyboard::TertiaryModifier) {
2105 case GDK_SCROLL_RIGHT:
2109 case GDK_SCROLL_DOWN:
2110 if (ev->state & Keyboard::TertiaryModifier) {
2122 Mixer_UI::parameter_changed (string const & p)
2124 if (p == "show-group-tabs") {
2125 bool const s = _session->config.get_show_group_tabs ();
2127 _group_tabs->show ();
2129 _group_tabs->hide ();
2131 } else if (p == "default-narrow_ms") {
2132 bool const s = UIConfiguration::instance().get_default_narrow_ms ();
2133 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
2134 (*i)->set_width_enum (s ? Narrow : Wide, this);
2136 } else if (p == "remote-model") {
2137 reset_remote_control_ids ();
2138 } else if (p == "use-monitor-bus") {
2139 if (_session && !_session->monitor_out()) {
2140 monitor_section_detached ();
2146 Mixer_UI::set_route_group_activation (RouteGroup* g, bool a)
2148 g->set_active (a, this);
2152 Mixer_UI::plugin_selector()
2154 #ifdef DEFER_PLUGIN_SELECTOR_LOAD
2155 if (!_plugin_selector)
2156 _plugin_selector = new PluginSelector (PluginManager::instance());
2159 return _plugin_selector;
2163 Mixer_UI::setup_track_display ()
2165 track_model = ListStore::create (track_columns);
2166 track_display.set_model (track_model);
2167 track_display.append_column (_("Strips"), track_columns.text);
2168 track_display.append_column (_("Show"), track_columns.visible);
2169 track_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
2170 track_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
2171 track_display.get_column (0)->set_expand(true);
2172 track_display.get_column (1)->set_expand(false);
2173 track_display.get_column (0)->set_sizing (Gtk::TREE_VIEW_COLUMN_FIXED);
2174 track_display.set_name (X_("EditGroupList"));
2175 track_display.get_selection()->set_mode (Gtk::SELECTION_NONE);
2176 track_display.set_reorderable (true);
2177 track_display.set_headers_visible (true);
2178 track_display.set_can_focus(false);
2180 track_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_delete));
2181 track_model->signal_rows_reordered().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_reorder));
2183 CellRendererToggle* track_list_visible_cell = dynamic_cast<CellRendererToggle*>(track_display.get_column_cell_renderer (1));
2184 track_list_visible_cell->property_activatable() = true;
2185 track_list_visible_cell->property_radio() = false;
2186 track_list_visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &Mixer_UI::track_visibility_changed));
2188 track_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::track_display_button_press), false);
2190 track_display_scroller.add (track_display);
2191 track_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2193 VBox* v = manage (new VBox);
2195 v->pack_start (track_display_scroller, true, true);
2197 Button* b = manage (new Button);
2199 Widget* w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
2203 b->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus));
2205 v->pack_start (*b, false, false);
2207 track_display_frame.set_name("BaseFrame");
2208 track_display_frame.set_shadow_type (Gtk::SHADOW_IN);
2209 track_display_frame.add (*v);
2211 track_display_scroller.show();
2212 track_display_frame.show();
2213 track_display.show();
2217 Mixer_UI::new_track_or_bus ()
2219 ARDOUR_UI::instance()->add_route ();
2223 Mixer_UI::update_title ()
2225 if (!own_window()) {
2232 if (_session->snap_name() != _session->name()) {
2233 n = _session->snap_name ();
2235 n = _session->name ();
2238 if (_session->dirty ()) {
2242 WindowTitle title (n);
2243 title += S_("Window|Mixer");
2244 title += Glib::get_application_name ();
2245 own_window()->set_title (title.get_string());
2249 WindowTitle title (S_("Window|Mixer"));
2250 title += Glib::get_application_name ();
2251 own_window()->set_title (title.get_string());
2256 Mixer_UI::strip_by_x (int x)
2258 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
2261 (*i)->translate_coordinates (_content, 0, 0, x1, y);
2262 x2 = x1 + (*i)->get_width();
2264 if (x >= x1 && x <= x2) {
2273 Mixer_UI::set_route_targets_for_operation ()
2275 _route_targets.clear ();
2277 if (!_selection.empty()) {
2278 _route_targets = _selection.routes;
2282 // removed "implicit" selections of strips, after discussion on IRC
2287 Mixer_UI::monitor_section_going_away ()
2289 if (_monitor_section) {
2290 monitor_section_detached ();
2291 out_packer.remove (_monitor_section->tearoff());
2292 _monitor_section->set_session (0);
2293 delete _monitor_section;
2294 _monitor_section = 0;
2299 Mixer_UI::toggle_midi_input_active (bool flip_others)
2301 boost::shared_ptr<RouteList> rl (new RouteList);
2304 set_route_targets_for_operation ();
2306 for (RouteUISelection::iterator r = _route_targets.begin(); r != _route_targets.end(); ++r) {
2307 boost::shared_ptr<MidiTrack> mt = (*r)->midi_track();
2310 rl->push_back ((*r)->route());
2311 onoff = !mt->input_active();
2315 _session->set_exclusive_input_active (rl, onoff, flip_others);
2319 Mixer_UI::maximise_mixer_space ()
2321 if (!own_window()) {
2329 _window->fullscreen ();
2334 Mixer_UI::restore_mixer_space ()
2336 if (!own_window()) {
2344 own_window()->unfullscreen();
2349 Mixer_UI::monitor_section_attached ()
2351 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
2352 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2353 act->set_sensitive (true);
2354 tact->set_active ();
2358 Mixer_UI::monitor_section_detached ()
2360 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
2361 act->set_sensitive (false);
2365 Mixer_UI::store_current_favorite_order ()
2367 typedef Gtk::TreeModel::Children type_children;
2368 type_children children = favorite_plugins_model->children();
2369 favorite_order.clear();
2370 for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter)
2372 Gtk::TreeModel::Row row = *iter;
2373 ARDOUR::PluginPresetPtr ppp = row[favorite_plugins_columns.plugin];
2374 favorite_order.push_back (ppp->_pip);
2375 std::string name = row[favorite_plugins_columns.name];
2376 favorite_ui_state[(*ppp->_pip).unique_id] = favorite_plugins_display.row_expanded (favorite_plugins_model->get_path(iter));
2381 Mixer_UI::save_favorite_ui_state (const TreeModel::iterator& iter, const TreeModel::Path& path)
2383 Gtk::TreeModel::Row row = *iter;
2384 ARDOUR::PluginPresetPtr ppp = row[favorite_plugins_columns.plugin];
2386 favorite_ui_state[(*ppp->_pip).unique_id] = favorite_plugins_display.row_expanded (favorite_plugins_model->get_path(iter));
2390 Mixer_UI::refiller (PluginInfoList& result, const PluginInfoList& plugs)
2392 PluginManager& manager (PluginManager::instance());
2393 for (PluginInfoList::const_iterator i = plugs.begin(); i != plugs.end(); ++i) {
2394 if (manager.get_status (*i) != PluginManager::Favorite) {
2397 result.push_back (*i);
2401 struct PluginCustomSorter {
2403 bool operator() (PluginInfoPtr a, PluginInfoPtr b) const {
2404 PluginInfoList::const_iterator aiter = _user.begin();
2405 PluginInfoList::const_iterator biter = _user.begin();
2406 while (aiter != _user.end()) { if ((*aiter)->unique_id == a->unique_id) { break; } ++aiter; }
2407 while (biter != _user.end()) { if ((*biter)->unique_id == b->unique_id) { break; } ++biter; }
2409 if (aiter != _user.end() && biter != _user.end()) {
2410 return std::distance (_user.begin(), aiter) < std::distance (_user.begin(), biter);
2412 if (aiter != _user.end()) {
2415 if (biter != _user.end()) {
2418 return ARDOUR::cmp_nocase((*a).name, (*b).name) == -1;
2420 PluginCustomSorter(PluginInfoList user) : _user (user) {}
2422 PluginInfoList _user;
2426 Mixer_UI::refill_favorite_plugins ()
2428 PluginInfoList plugs;
2429 PluginManager& mgr (PluginManager::instance());
2432 refiller (plugs, mgr.lv2_plugin_info ());
2434 #ifdef WINDOWS_VST_SUPPORT
2435 refiller (plugs, mgr.windows_vst_plugin_info ());
2437 #ifdef LXVST_SUPPORT
2438 refiller (plugs, mgr.lxvst_plugin_info ());
2440 #ifdef AUDIOUNIT_SUPPORT
2441 refiller (plugs, mgr.au_plugin_info ());
2443 refiller (plugs, mgr.ladspa_plugin_info ());
2444 refiller (plugs, mgr.lua_plugin_info ());
2446 store_current_favorite_order ();
2448 PluginCustomSorter cmp (favorite_order);
2451 favorite_order = plugs;
2453 sync_treeview_from_favorite_order ();
2457 Mixer_UI::sync_treeview_favorite_ui_state (const TreeModel::Path& path, const TreeModel::iterator&)
2460 if (!(iter = favorite_plugins_model->get_iter (path))) {
2463 ARDOUR::PluginPresetPtr ppp = (*iter)[favorite_plugins_columns.plugin];
2467 PluginInfoPtr pip = ppp->_pip;
2468 if (favorite_ui_state.find (pip->unique_id) != favorite_ui_state.end ()) {
2469 if (favorite_ui_state[pip->unique_id]) {
2470 favorite_plugins_display.expand_row (path, true);
2476 Mixer_UI::sync_treeview_from_favorite_order ()
2478 favorite_plugins_model->clear ();
2479 for (PluginInfoList::const_iterator i = favorite_order.begin(); i != favorite_order.end(); ++i) {
2480 PluginInfoPtr pip = (*i);
2482 TreeModel::Row newrow = *(favorite_plugins_model->append());
2483 newrow[favorite_plugins_columns.name] = (*i)->name;
2484 newrow[favorite_plugins_columns.plugin] = PluginPresetPtr (new PluginPreset(pip));
2489 vector<ARDOUR::Plugin::PresetRecord> presets = (*i)->get_presets (true);
2490 for (vector<ARDOUR::Plugin::PresetRecord>::const_iterator j = presets.begin(); j != presets.end(); ++j) {
2491 Gtk::TreeModel::Row child_row = *(favorite_plugins_model->append (newrow.children()));
2492 child_row[favorite_plugins_columns.name] = (*j).label;
2493 child_row[favorite_plugins_columns.plugin] = PluginPresetPtr (new PluginPreset(pip, &(*j)));
2495 if (favorite_ui_state.find (pip->unique_id) != favorite_ui_state.end ()) {
2496 if (favorite_ui_state[pip->unique_id]) {
2497 favorite_plugins_display.expand_row (favorite_plugins_model->get_path(newrow), true);
2504 Mixer_UI::popup_note_context_menu (GdkEventButton *ev)
2506 using namespace Gtk::Menu_Helpers;
2508 Gtk::Menu* m = manage (new Menu);
2509 MenuList& items = m->items ();
2511 if (_selection.routes.empty()) {
2512 items.push_back (MenuElem (_("No Track/Bus is selected.")));
2514 items.push_back (MenuElem (_("Add at the top"),
2515 sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddTop)));
2516 items.push_back (MenuElem (_("Add Pre-Fader"),
2517 sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddPreFader)));
2518 items.push_back (MenuElem (_("Add Post-Fader"),
2519 sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddPostFader)));
2520 items.push_back (MenuElem (_("Add at the end"),
2521 sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddBottom)));
2524 items.push_back (SeparatorElem());
2526 items.push_back (MenuElem (_("Remove from favorites"), sigc::mem_fun (*this, &Mixer_UI::remove_selected_from_favorites)));
2528 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2529 if (ppp && ppp->_preset.valid && ppp->_preset.user) {
2530 // we cannot currently delete AU presets
2531 if (!ppp->_pip || ppp->_pip->type != AudioUnit) {
2532 items.push_back (MenuElem (_("Delete Preset"), sigc::mem_fun (*this, &Mixer_UI::delete_selected_preset)));
2536 m->popup (ev->button, ev->time);
2540 Mixer_UI::plugin_row_button_press (GdkEventButton *ev)
2542 if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 3) ) {
2543 TreeModel::Path path;
2544 TreeViewColumn* column;
2546 if (favorite_plugins_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
2547 Glib::RefPtr<Gtk::TreeView::Selection> selection = favorite_plugins_display.get_selection();
2549 selection->unselect_all();
2550 selection->select(path);
2553 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2555 popup_note_context_menu (ev);
2563 Mixer_UI::selected_plugin ()
2565 Glib::RefPtr<Gtk::TreeView::Selection> selection = favorite_plugins_display.get_selection();
2567 return PluginPresetPtr();
2569 Gtk::TreeModel::iterator iter = selection->get_selected();
2571 return PluginPresetPtr();
2573 return (*iter)[favorite_plugins_columns.plugin];
2577 Mixer_UI::add_selected_processor (ProcessorPosition pos)
2579 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2581 add_favorite_processor (ppp, pos);
2586 Mixer_UI::delete_selected_preset ()
2591 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2592 if (!ppp || !ppp->_preset.valid || !ppp->_preset.user) {
2595 PluginPtr plugin = ppp->_pip->load (*_session);
2596 plugin->get_presets();
2597 plugin->remove_preset (ppp->_preset.label);
2601 Mixer_UI::remove_selected_from_favorites ()
2603 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2607 PluginManager::PluginStatusType status = PluginManager::Normal;
2608 PluginManager& manager (PluginManager::instance());
2610 manager.set_status (ppp->_pip->type, ppp->_pip->unique_id, status);
2611 manager.save_statuses ();
2615 Mixer_UI::plugin_row_activated (const TreeModel::Path& path, TreeViewColumn* column)
2618 if (!(iter = favorite_plugins_model->get_iter (path))) {
2621 ARDOUR::PluginPresetPtr ppp = (*iter)[favorite_plugins_columns.plugin];
2622 add_favorite_processor (ppp, AddPreFader); // TODO: preference?!
2626 Mixer_UI::add_favorite_processor (ARDOUR::PluginPresetPtr ppp, ProcessorPosition pos)
2628 if (!_session || _selection.routes.empty()) {
2632 PluginInfoPtr pip = ppp->_pip;
2633 for (RouteUISelection::iterator i = _selection.routes.begin(); i != _selection.routes.end(); ++i) {
2634 boost::shared_ptr<ARDOUR::Route> rt = (*i)->route();
2635 if (!rt) { continue; }
2637 PluginPtr p = pip->load (*_session);
2638 if (!p) { continue; }
2640 if (ppp->_preset.valid) {
2641 p->load_preset (ppp->_preset);
2644 Route::ProcessorStreams err;
2645 boost::shared_ptr<Processor> processor (new PluginInsert (*_session, p));
2649 rt->add_processor_by_index (processor, 0, &err, Config->get_new_plugins_active ());
2652 rt->add_processor (processor, PreFader, &err, Config->get_new_plugins_active ());
2659 boost::shared_ptr<Processor> np = rt->nth_processor (idx);
2663 if (!np->display_to_user()) {
2666 if (boost::dynamic_pointer_cast<Amp> (np) && // Fader, not Trim
2667 boost::dynamic_pointer_cast<Amp> (np)->gain_control()->parameter().type() == GainAutomation) {
2672 rt->add_processor_by_index (processor, ++pos, &err, Config->get_new_plugins_active ());
2676 rt->add_processor_by_index (processor, -1, &err, Config->get_new_plugins_active ());
2683 PluginTreeStore::row_drop_possible_vfunc(const Gtk::TreeModel::Path& dest, const Gtk::SelectionData& data) const
2685 if (data.get_target() != "GTK_TREE_MODEL_ROW") {
2689 // only allow to re-order top-level items
2691 if (TreePath::get_from_selection_data (data, src)) {
2692 if (src.up() && src.up()) {
2697 // don't allow to drop as child-rows.
2698 Gtk::TreeModel::Path _dest = dest; // un const
2699 const bool is_child = _dest.up (); // explicit bool for clang
2700 if (!is_child || _dest.empty ()) {
2707 Mixer_UI::plugin_drop (const Glib::RefPtr<Gdk::DragContext>&, const Gtk::SelectionData& data)
2709 if (data.get_target() != "PluginPresetPtr") {
2712 if (data.get_length() != sizeof (PluginPresetPtr)) {
2715 const void *d = data.get_data();
2716 const PluginPresetPtr ppp = *(static_cast<const PluginPresetPtr*> (d));
2718 PluginManager::PluginStatusType status = PluginManager::Favorite;
2719 PluginManager& manager (PluginManager::instance());
2721 manager.set_status (ppp->_pip->type, ppp->_pip->unique_id, status);
2722 manager.save_statuses ();
2726 Mixer_UI::do_vca_assign (boost::shared_ptr<VCA> vca)
2728 /* call protected MixerActor:: method */
2733 Mixer_UI::do_vca_unassign (boost::shared_ptr<VCA> vca)
2735 /* call protected MixerActor:: method */