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;
1237 if (no_track_list_redisplay) {
1241 container_clear (vca_packer);
1243 for (i = rows.begin(); i != rows.end(); ++i) {
1245 VCAMasterStrip* vms = (*i)[track_columns.vca];
1248 vca_packer.pack_start (*vms, false, false);
1253 MixerStrip* strip = (*i)[track_columns.strip];
1256 /* we're in the middle of changing a row, don't worry */
1260 bool const visible = (*i)[track_columns.visible];
1263 strip->set_gui_property ("visible", true);
1265 if (strip->packed()) {
1267 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1268 out_packer.reorder_child (*strip, -1);
1271 strip_packer.reorder_child (*strip, -1); /* put at end */
1276 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1277 out_packer.pack_start (*strip, false, false);
1279 strip_packer.pack_start (*strip, false, false);
1281 strip->set_packed (true);
1286 strip->set_gui_property ("visible", false);
1288 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1289 /* do nothing, these cannot be hidden */
1291 if (strip->packed()) {
1292 strip_packer.remove (*strip);
1293 strip->set_packed (false);
1299 _group_tabs->set_dirty ();
1303 Mixer_UI::strip_width_changed ()
1305 _group_tabs->set_dirty ();
1308 TreeModel::Children rows = track_model->children();
1309 TreeModel::Children::iterator i;
1312 for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
1313 MixerStrip* strip = (*i)[track_columns.strip];
1319 bool visible = (*i)[track_columns.visible];
1322 strip->queue_draw();
1330 Mixer_UI::initial_track_display ()
1332 boost::shared_ptr<RouteList> routes = _session->get_routes();
1333 RouteList copy (*routes);
1334 ARDOUR::SignalOrderRouteSorter sorter;
1339 Unwinder<bool> uw1 (no_track_list_redisplay, true);
1340 Unwinder<bool> uw2 (ignore_reorder, true);
1342 track_model->clear ();
1343 VCAList vcas = _session->vca_manager().vcas();
1348 _session->sync_order_keys ();
1350 redisplay_track_list ();
1354 Mixer_UI::show_track_list_menu ()
1356 if (track_menu == 0) {
1357 build_track_menu ();
1360 track_menu->popup (1, gtk_get_current_event_time());
1364 Mixer_UI::track_display_button_press (GdkEventButton* ev)
1366 if (Keyboard::is_context_menu_event (ev)) {
1367 show_track_list_menu ();
1375 Mixer_UI::build_track_menu ()
1377 using namespace Menu_Helpers;
1378 using namespace Gtk;
1380 track_menu = new Menu;
1381 track_menu->set_name ("ArdourContextMenu");
1382 MenuList& items = track_menu->items();
1384 items.push_back (MenuElem (_("Show All"), sigc::mem_fun(*this, &Mixer_UI::show_all_routes)));
1385 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun(*this, &Mixer_UI::hide_all_routes)));
1386 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
1387 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
1388 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus)));
1389 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
1390 items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &Mixer_UI::show_all_miditracks)));
1391 items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &Mixer_UI::hide_all_miditracks)));
1396 Mixer_UI::strip_property_changed (const PropertyChange& what_changed, MixerStrip* mx)
1398 if (!what_changed.contains (ARDOUR::Properties::name)) {
1402 ENSURE_GUI_THREAD (*this, &Mixer_UI::strip_name_changed, what_changed, mx)
1404 TreeModel::Children rows = track_model->children();
1405 TreeModel::Children::iterator i;
1407 for (i = rows.begin(); i != rows.end(); ++i) {
1408 if ((*i)[track_columns.strip] == mx) {
1409 (*i)[track_columns.text] = mx->route()->name();
1414 error << _("track display list item for renamed strip not found!") << endmsg;
1418 Mixer_UI::group_display_button_press (GdkEventButton* ev)
1420 TreeModel::Path path;
1421 TreeViewColumn* column;
1425 if (!group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
1426 _group_tabs->get_menu(0)->popup (1, ev->time);
1430 TreeIter iter = group_model->get_iter (path);
1432 _group_tabs->get_menu(0)->popup (1, ev->time);
1436 RouteGroup* group = (*iter)[group_columns.group];
1438 if (Keyboard::is_context_menu_event (ev)) {
1439 _group_tabs->get_menu(group)->popup (1, ev->time);
1443 switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
1445 if (Keyboard::is_edit_event (ev)) {
1447 // edit_route_group (group);
1449 group_display.queue_draw();
1458 bool visible = (*iter)[group_columns.visible];
1459 (*iter)[group_columns.visible] = !visible;
1461 group_display.queue_draw();
1474 Mixer_UI::activate_all_route_groups ()
1476 _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), true));
1480 Mixer_UI::disable_all_route_groups ()
1482 _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), false));
1486 Mixer_UI::route_groups_changed ()
1488 ENSURE_GUI_THREAD (*this, &Mixer_UI::route_groups_changed);
1490 _in_group_rebuild_or_clear = true;
1492 /* just rebuild the while thing */
1494 group_model->clear ();
1497 /* this is currently not used,
1498 * Mixer_UI::group_display_button_press() has a case for it,
1499 * and a commented edit_route_group() but that's n/a since 2011.
1501 * This code is left as reminder that
1502 * row[group_columns.group] = 0 has special meaning.
1506 row = *(group_model->append());
1507 row[group_columns.visible] = true;
1508 row[group_columns.text] = (_("-all-"));
1509 row[group_columns.group] = 0;
1513 _session->foreach_route_group (sigc::mem_fun (*this, &Mixer_UI::add_route_group));
1515 _group_tabs->set_dirty ();
1516 _in_group_rebuild_or_clear = false;
1520 Mixer_UI::new_route_group ()
1524 _group_tabs->run_new_group_dialog (rl);
1528 Mixer_UI::remove_selected_route_group ()
1530 Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1531 TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1537 TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1540 /* selection mode is single, so rows.begin() is it */
1542 if ((iter = group_model->get_iter (*i))) {
1544 RouteGroup* rg = (*iter)[group_columns.group];
1547 _session->remove_route_group (*rg);
1553 Mixer_UI::route_group_property_changed (RouteGroup* group, const PropertyChange& change)
1555 if (in_group_row_change) {
1559 /* force an update of any mixer strips that are using this group,
1560 otherwise mix group names don't change in mixer strips
1563 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1564 if ((*i)->route_group() == group) {
1565 (*i)->route_group_changed();
1569 TreeModel::iterator i;
1570 TreeModel::Children rows = group_model->children();
1571 Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1573 in_group_row_change = true;
1575 for (i = rows.begin(); i != rows.end(); ++i) {
1576 if ((*i)[group_columns.group] == group) {
1577 (*i)[group_columns.visible] = !group->is_hidden ();
1578 (*i)[group_columns.text] = group->name ();
1583 in_group_row_change = false;
1585 if (change.contains (Properties::name)) {
1586 _group_tabs->set_dirty ();
1589 for (list<MixerStrip*>::iterator j = strips.begin(); j != strips.end(); ++j) {
1590 if ((*j)->route_group() == group) {
1591 if (group->is_hidden ()) {
1601 Mixer_UI::show_mixer_list (bool yn)
1604 list_vpacker.show ();
1606 //if user wants to show the pane, we should make sure that it is wide enough to be visible
1607 int width = list_hpane.get_position();
1609 list_hpane.set_position(40);
1612 list_vpacker.hide ();
1615 _show_mixer_list = yn;
1619 Mixer_UI::show_monitor_section (bool yn)
1621 if (!monitor_section()) {
1624 if (monitor_section()->tearoff().torn_off()) {
1629 monitor_section()->tearoff().show();
1631 monitor_section()->tearoff().hide();
1636 Mixer_UI::route_group_name_edit (const std::string& path, const std::string& new_text)
1641 if ((iter = group_model->get_iter (path))) {
1643 if ((group = (*iter)[group_columns.group]) == 0) {
1647 if (new_text != group->name()) {
1648 group->set_name (new_text);
1654 Mixer_UI::route_group_row_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator& iter)
1658 if (in_group_row_change) {
1662 if ((group = (*iter)[group_columns.group]) == 0) {
1666 std::string name = (*iter)[group_columns.text];
1668 if (name != group->name()) {
1669 group->set_name (name);
1672 bool hidden = !(*iter)[group_columns.visible];
1674 if (hidden != group->is_hidden ()) {
1675 group->set_hidden (hidden, this);
1679 /** Called when a group model row is deleted, but also when the model is
1680 * reordered by a user drag-and-drop; the latter is what we are
1681 * interested in here.
1684 Mixer_UI::route_group_row_deleted (Gtk::TreeModel::Path const &)
1686 if (_in_group_rebuild_or_clear) {
1690 /* Re-write the session's route group list so that the new order is preserved */
1692 list<RouteGroup*> new_list;
1694 Gtk::TreeModel::Children children = group_model->children();
1695 for (Gtk::TreeModel::Children::iterator i = children.begin(); i != children.end(); ++i) {
1696 RouteGroup* g = (*i)[group_columns.group];
1698 new_list.push_back (g);
1702 _session->reorder_route_groups (new_list);
1707 Mixer_UI::add_route_group (RouteGroup* group)
1709 ENSURE_GUI_THREAD (*this, &Mixer_UI::add_route_group, group)
1712 in_group_row_change = true;
1714 TreeModel::Row row = *(group_model->append());
1715 row[group_columns.visible] = !group->is_hidden ();
1716 row[group_columns.group] = group;
1717 if (!group->name().empty()) {
1718 row[group_columns.text] = group->name();
1720 row[group_columns.text] = _("unnamed");
1724 group->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::route_group_property_changed, this, group, _1), gui_context());
1727 TreeViewColumn* col = group_display.get_column (0);
1728 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
1729 group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true);
1732 _group_tabs->set_dirty ();
1734 in_group_row_change = false;
1738 Mixer_UI::strip_scroller_button_release (GdkEventButton* ev)
1740 using namespace Menu_Helpers;
1742 if (Keyboard::is_context_menu_event (ev)) {
1743 ARDOUR_UI::instance()->add_route ();
1751 Mixer_UI::scroller_drag_data_received (const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, const Gtk::SelectionData& data, guint info, guint time)
1753 printf ("Mixer_UI::scroller_drag_data_received\n");
1754 if (data.get_target() != "PluginFavoritePtr") {
1755 context->drag_finish (false, false, time);
1759 const void * d = data.get_data();
1760 const Gtkmm2ext::DnDTreeView<ARDOUR::PluginPresetPtr>* tv = reinterpret_cast<const Gtkmm2ext::DnDTreeView<ARDOUR::PluginPresetPtr>*>(d);
1762 PluginPresetList nfos;
1764 tv->get_object_drag_data (nfos, &source);
1766 Route::ProcessorList pl;
1769 for (list<PluginPresetPtr>::const_iterator i = nfos.begin(); i != nfos.end(); ++i) {
1770 PluginPresetPtr ppp = (*i);
1771 PluginInfoPtr pip = ppp->_pip;
1772 if (!pip->is_instrument ()) {
1775 ARDOUR_UI::instance()->session_add_midi_track (NULL, 1, _("MIDI"), Config->get_strict_io (), pip, ppp->_preset.valid ? &ppp->_preset : 0);
1779 context->drag_finish (ok, false, time);
1783 Mixer_UI::set_strip_width (Width w, bool save)
1787 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1788 (*i)->set_width_enum (w, save ? (*i)->width_owner() : this);
1793 struct PluginStateSorter {
1795 bool operator() (PluginInfoPtr a, PluginInfoPtr b) const {
1796 std::list<std::string>::const_iterator aiter = std::find(_user.begin(), _user.end(), (*a).unique_id);
1797 std::list<std::string>::const_iterator biter = std::find(_user.begin(), _user.end(), (*b).unique_id);
1798 if (aiter != _user.end() && biter != _user.end()) {
1799 return std::distance (_user.begin(), aiter) < std::distance (_user.begin(), biter);
1801 if (aiter != _user.end()) {
1804 if (biter != _user.end()) {
1807 return ARDOUR::cmp_nocase((*a).name, (*b).name) == -1;
1810 PluginStateSorter(std::list<std::string> user) : _user (user) {}
1812 std::list<std::string> _user;
1816 Mixer_UI::set_state (const XMLNode& node, int version)
1818 XMLProperty const * prop;
1820 Tabbable::set_state (node, version);
1822 if ((prop = node.property ("narrow-strips"))) {
1823 if (string_is_affirmative (prop->value())) {
1824 set_strip_width (Narrow);
1826 set_strip_width (Wide);
1830 if ((prop = node.property ("show-mixer"))) {
1831 if (string_is_affirmative (prop->value())) {
1836 if ((prop = node.property ("maximised"))) {
1837 bool yn = string_is_affirmative (prop->value());
1838 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalMixer"));
1840 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1841 bool fs = tact && tact->get_active();
1843 ActionManager::do_action ("Common", "ToggleMaximalMixer");
1847 if ((prop = node.property ("show-mixer-list"))) {
1848 bool yn = string_is_affirmative (prop->value());
1849 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMixerList"));
1851 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1853 /* do it twice to force the change */
1854 tact->set_active (!yn);
1855 tact->set_active (yn);
1859 XMLNode* plugin_order;
1860 if ((plugin_order = find_named_node (node, "PluginOrder")) != 0) {
1861 store_current_favorite_order ();
1862 std::list<string> order;
1863 const XMLNodeList& kids = plugin_order->children("PluginInfo");
1864 XMLNodeConstIterator i;
1865 for (i = kids.begin(); i != kids.end(); ++i) {
1866 if ((prop = (*i)->property ("unique-id"))) {
1867 std::string unique_id = prop->value();
1868 order.push_back (unique_id);
1869 if ((prop = (*i)->property ("expanded"))) {
1870 favorite_ui_state[unique_id] = string_is_affirmative (prop->value());
1874 PluginStateSorter cmp (order);
1875 favorite_order.sort (cmp);
1876 sync_treeview_from_favorite_order ();
1882 Mixer_UI::get_state ()
1884 XMLNode* node = new XMLNode (X_("Mixer"));
1887 node->add_child_nocopy (Tabbable::get_state());
1889 snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (rhs_pane1, true));
1890 node->add_property(X_("mixer-rhs-pane1-pos"), string(buf));
1891 snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (rhs_pane2, true));
1892 node->add_property(X_("mixer-rhs_pane2-pos"), string(buf));
1893 snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (list_hpane, false));
1894 node->add_property(X_("mixer-list-hpane-pos"), string(buf));
1895 snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (inner_pane, false));
1896 node->add_property(X_("mixer-inner-pane-pos"), string(buf));
1898 node->add_property ("narrow-strips", _strip_width == Narrow ? "yes" : "no");
1899 node->add_property ("show-mixer", _visible ? "yes" : "no");
1900 node->add_property ("show-mixer-list", _show_mixer_list ? "yes" : "no");
1901 node->add_property ("maximised", _maximised ? "yes" : "no");
1903 store_current_favorite_order ();
1904 XMLNode* plugin_order = new XMLNode ("PluginOrder");
1906 for (PluginInfoList::const_iterator i = favorite_order.begin(); i != favorite_order.end(); ++i, ++cnt) {
1907 XMLNode* p = new XMLNode ("PluginInfo");
1908 p->add_property ("sort", cnt);
1909 p->add_property ("unique-id", (*i)->unique_id);
1910 if (favorite_ui_state.find ((*i)->unique_id) != favorite_ui_state.end ()) {
1911 p->add_property ("expanded", favorite_ui_state[(*i)->unique_id]);
1913 plugin_order->add_child_nocopy (*p);
1915 node->add_child_nocopy (*plugin_order);
1921 Mixer_UI::pane_allocation_handler (Allocation& allocation, Gtk::Paned* which)
1924 XMLProperty* prop = 0;
1925 XMLNode* geometry = ARDOUR_UI::instance()->mixer_settings();
1926 int height = default_height;
1927 static bool done[4] = { false, false, false, false };
1929 /* Gtk::Paned behaves very oddly and rather undesirably. Setting the
1930 * position is a crapshoot if you time it incorrectly with the overall
1931 * sizing of the Paned. For example, if you might retrieve the size with
1932 * ::get_position() and then later call ::set_position() on a Paned at
1933 * a time when its allocation is different than it was when you retrieved
1934 * the position. The position will be interpreted as the size of the
1935 * first (top or left) child widget. If packing/size allocation later
1936 * resizes the Paned to a (final) smaller size, the position will be
1937 * used in ways that mean that the Paned ends up NOT in the same state
1938 * that it was in when you originally saved the position.
1940 * Concrete example: Paned is 800 pixels wide, position is 400
1941 * (halfway). Save position as 400. During program restart, set
1942 * position to 400, before Paned has been allocated any space. Paned
1943 * ends up initially sized to 1200 pixels. Position is now 1/3 of the
1944 * way across/down. Subsequent resizes will leave the position 1/3 of
1945 * the way across, rather than leaving it as a fixed pixel
1946 * position. Eventually, the Paned ends up 800 pixels wide/high again,
1947 * but the position is now 267, not 400.
1951 * We deal with this by using two strategies:
1953 * 1) only set the position if the allocated size of the Paned is at
1954 * least as big as it needs to be for the position to make sense.
1956 * 2) in recent versions of Ardour, save the position as a fraction,
1957 * and restore it using that fraction.
1959 * So, we will only call ::set_position() AFTER the Paned is of a
1960 * sensible size, and then in addition, we will set the position in a
1961 * way that will be maintained as/when/if the Paned is resized.
1963 * Once we've called ::set_position() on a Paned, we don't do it
1967 if (which == static_cast<Gtk::Paned*> (&rhs_pane1)) {
1973 if (!geometry || (prop = geometry->property("mixer-rhs-pane1-pos")) == 0) {
1976 pos = atof (prop->value());
1980 /* older versions of Ardour stored absolute position */
1981 if ((done[0] = (allocation.get_height() > pos))) {
1982 rhs_pane1.set_position (pos);
1985 if ((done[0] = (allocation.get_height() > 1.0/pos))) {
1986 paned_set_position_as_fraction (rhs_pane1, pos, true);
1991 if (which == static_cast<Gtk::Paned*> (&rhs_pane2)) {
1997 if (!geometry || (prop = geometry->property("mixer-rhs-pane2-pos")) == 0) {
1998 pos = 2 * height / 3;
2000 pos = atof (prop->value());
2004 /* older versions of Ardour stored absolute position */
2005 if ((done[1] = (allocation.get_height() > pos))) {
2006 rhs_pane2.set_position (pos);
2009 if ((done[1] = (allocation.get_height() > 1.0/pos))) {
2010 paned_set_position_as_fraction (rhs_pane2, pos, true);
2015 if (which == static_cast<Gtk::Paned*> (&list_hpane)) {
2021 if (!geometry || (prop = geometry->property("mixer-list-hpane-pos")) == 0) {
2022 pos = std::max ((float)100, rintf ((float) 125 * UIConfiguration::instance().get_ui_scale()));
2024 pos = max (0.1, atof (prop->value ()));
2028 if ((done[2] = (allocation.get_width() > pos))) {
2029 list_hpane.set_position (pos);
2032 if ((done[2] = (allocation.get_width() > 1.0/pos))) {
2033 paned_set_position_as_fraction (list_hpane, pos, false);
2038 if (which == static_cast<Gtk::Paned*> (&inner_pane)) {
2044 if (!geometry || (prop = geometry->property("mixer-inner-pane-pos")) == 0) {
2045 pos = std::max ((float)100, rintf ((float) 125 * UIConfiguration::instance().get_ui_scale()));
2047 pos = max (0.1, atof (prop->value ()));
2051 /* older versions of Ardour stored absolute position */
2052 if ((done[3] = (allocation.get_width() > pos))) {
2053 inner_pane.set_position (pos);
2056 if ((done[3] = (allocation.get_width() > 1.0/pos))) {
2057 paned_set_position_as_fraction (inner_pane, pos, false);
2064 Mixer_UI::scroll_left ()
2066 if (!scroller.get_hscrollbar()) return;
2067 Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
2068 /* stupid GTK: can't rely on clamping across versions */
2069 scroller.get_hscrollbar()->set_value (max (adj->get_lower(), adj->get_value() - adj->get_step_increment()));
2073 Mixer_UI::scroll_right ()
2075 if (!scroller.get_hscrollbar()) return;
2076 Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
2077 /* stupid GTK: can't rely on clamping across versions */
2078 scroller.get_hscrollbar()->set_value (min (adj->get_upper(), adj->get_value() + adj->get_step_increment()));
2082 Mixer_UI::on_scroll_event (GdkEventScroll* ev)
2084 switch (ev->direction) {
2085 case GDK_SCROLL_LEFT:
2089 if (ev->state & Keyboard::TertiaryModifier) {
2095 case GDK_SCROLL_RIGHT:
2099 case GDK_SCROLL_DOWN:
2100 if (ev->state & Keyboard::TertiaryModifier) {
2112 Mixer_UI::parameter_changed (string const & p)
2114 if (p == "show-group-tabs") {
2115 bool const s = _session->config.get_show_group_tabs ();
2117 _group_tabs->show ();
2119 _group_tabs->hide ();
2121 } else if (p == "default-narrow_ms") {
2122 bool const s = UIConfiguration::instance().get_default_narrow_ms ();
2123 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
2124 (*i)->set_width_enum (s ? Narrow : Wide, this);
2126 } else if (p == "remote-model") {
2127 reset_remote_control_ids ();
2128 } else if (p == "use-monitor-bus") {
2129 if (_session && !_session->monitor_out()) {
2130 monitor_section_detached ();
2136 Mixer_UI::set_route_group_activation (RouteGroup* g, bool a)
2138 g->set_active (a, this);
2142 Mixer_UI::plugin_selector()
2144 #ifdef DEFER_PLUGIN_SELECTOR_LOAD
2145 if (!_plugin_selector)
2146 _plugin_selector = new PluginSelector (PluginManager::instance());
2149 return _plugin_selector;
2153 Mixer_UI::setup_track_display ()
2155 track_model = ListStore::create (track_columns);
2156 track_display.set_model (track_model);
2157 track_display.append_column (_("Strips"), track_columns.text);
2158 track_display.append_column (_("Show"), track_columns.visible);
2159 track_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
2160 track_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
2161 track_display.get_column (0)->set_expand(true);
2162 track_display.get_column (1)->set_expand(false);
2163 track_display.get_column (0)->set_sizing (Gtk::TREE_VIEW_COLUMN_FIXED);
2164 track_display.set_name (X_("EditGroupList"));
2165 track_display.get_selection()->set_mode (Gtk::SELECTION_NONE);
2166 track_display.set_reorderable (true);
2167 track_display.set_headers_visible (true);
2168 track_display.set_can_focus(false);
2170 track_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_delete));
2171 track_model->signal_rows_reordered().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_reorder));
2173 CellRendererToggle* track_list_visible_cell = dynamic_cast<CellRendererToggle*>(track_display.get_column_cell_renderer (1));
2174 track_list_visible_cell->property_activatable() = true;
2175 track_list_visible_cell->property_radio() = false;
2176 track_list_visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &Mixer_UI::track_visibility_changed));
2178 track_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::track_display_button_press), false);
2180 track_display_scroller.add (track_display);
2181 track_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2183 VBox* v = manage (new VBox);
2185 v->pack_start (track_display_scroller, true, true);
2187 Button* b = manage (new Button);
2189 Widget* w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
2193 b->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus));
2195 v->pack_start (*b, false, false);
2197 track_display_frame.set_name("BaseFrame");
2198 track_display_frame.set_shadow_type (Gtk::SHADOW_IN);
2199 track_display_frame.add (*v);
2201 track_display_scroller.show();
2202 track_display_frame.show();
2203 track_display.show();
2207 Mixer_UI::new_track_or_bus ()
2209 ARDOUR_UI::instance()->add_route ();
2213 Mixer_UI::update_title ()
2215 if (!own_window()) {
2222 if (_session->snap_name() != _session->name()) {
2223 n = _session->snap_name ();
2225 n = _session->name ();
2228 if (_session->dirty ()) {
2232 WindowTitle title (n);
2233 title += S_("Window|Mixer");
2234 title += Glib::get_application_name ();
2235 own_window()->set_title (title.get_string());
2239 WindowTitle title (S_("Window|Mixer"));
2240 title += Glib::get_application_name ();
2241 own_window()->set_title (title.get_string());
2246 Mixer_UI::strip_by_x (int x)
2248 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
2251 (*i)->translate_coordinates (_content, 0, 0, x1, y);
2252 x2 = x1 + (*i)->get_width();
2254 if (x >= x1 && x <= x2) {
2263 Mixer_UI::set_route_targets_for_operation ()
2265 _route_targets.clear ();
2267 if (!_selection.empty()) {
2268 _route_targets = _selection.routes;
2272 // removed "implicit" selections of strips, after discussion on IRC
2277 Mixer_UI::monitor_section_going_away ()
2279 if (_monitor_section) {
2280 monitor_section_detached ();
2281 out_packer.remove (_monitor_section->tearoff());
2282 _monitor_section->set_session (0);
2283 delete _monitor_section;
2284 _monitor_section = 0;
2289 Mixer_UI::toggle_midi_input_active (bool flip_others)
2291 boost::shared_ptr<RouteList> rl (new RouteList);
2294 set_route_targets_for_operation ();
2296 for (RouteUISelection::iterator r = _route_targets.begin(); r != _route_targets.end(); ++r) {
2297 boost::shared_ptr<MidiTrack> mt = (*r)->midi_track();
2300 rl->push_back ((*r)->route());
2301 onoff = !mt->input_active();
2305 _session->set_exclusive_input_active (rl, onoff, flip_others);
2309 Mixer_UI::maximise_mixer_space ()
2311 if (!own_window()) {
2319 _window->fullscreen ();
2324 Mixer_UI::restore_mixer_space ()
2326 if (!own_window()) {
2334 own_window()->unfullscreen();
2339 Mixer_UI::monitor_section_attached ()
2341 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
2342 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2343 act->set_sensitive (true);
2344 tact->set_active ();
2348 Mixer_UI::monitor_section_detached ()
2350 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
2351 act->set_sensitive (false);
2355 Mixer_UI::store_current_favorite_order ()
2357 typedef Gtk::TreeModel::Children type_children;
2358 type_children children = favorite_plugins_model->children();
2359 favorite_order.clear();
2360 for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter)
2362 Gtk::TreeModel::Row row = *iter;
2363 ARDOUR::PluginPresetPtr ppp = row[favorite_plugins_columns.plugin];
2364 favorite_order.push_back (ppp->_pip);
2365 std::string name = row[favorite_plugins_columns.name];
2366 favorite_ui_state[(*ppp->_pip).unique_id] = favorite_plugins_display.row_expanded (favorite_plugins_model->get_path(iter));
2371 Mixer_UI::save_favorite_ui_state (const TreeModel::iterator& iter, const TreeModel::Path& path)
2373 Gtk::TreeModel::Row row = *iter;
2374 ARDOUR::PluginPresetPtr ppp = row[favorite_plugins_columns.plugin];
2376 favorite_ui_state[(*ppp->_pip).unique_id] = favorite_plugins_display.row_expanded (favorite_plugins_model->get_path(iter));
2380 Mixer_UI::refiller (PluginInfoList& result, const PluginInfoList& plugs)
2382 PluginManager& manager (PluginManager::instance());
2383 for (PluginInfoList::const_iterator i = plugs.begin(); i != plugs.end(); ++i) {
2384 if (manager.get_status (*i) != PluginManager::Favorite) {
2387 result.push_back (*i);
2391 struct PluginCustomSorter {
2393 bool operator() (PluginInfoPtr a, PluginInfoPtr b) const {
2394 PluginInfoList::const_iterator aiter = _user.begin();
2395 PluginInfoList::const_iterator biter = _user.begin();
2396 while (aiter != _user.end()) { if ((*aiter)->unique_id == a->unique_id) { break; } ++aiter; }
2397 while (biter != _user.end()) { if ((*biter)->unique_id == b->unique_id) { break; } ++biter; }
2399 if (aiter != _user.end() && biter != _user.end()) {
2400 return std::distance (_user.begin(), aiter) < std::distance (_user.begin(), biter);
2402 if (aiter != _user.end()) {
2405 if (biter != _user.end()) {
2408 return ARDOUR::cmp_nocase((*a).name, (*b).name) == -1;
2410 PluginCustomSorter(PluginInfoList user) : _user (user) {}
2412 PluginInfoList _user;
2416 Mixer_UI::refill_favorite_plugins ()
2418 PluginInfoList plugs;
2419 PluginManager& mgr (PluginManager::instance());
2422 refiller (plugs, mgr.lv2_plugin_info ());
2424 #ifdef WINDOWS_VST_SUPPORT
2425 refiller (plugs, mgr.windows_vst_plugin_info ());
2427 #ifdef LXVST_SUPPORT
2428 refiller (plugs, mgr.lxvst_plugin_info ());
2430 #ifdef AUDIOUNIT_SUPPORT
2431 refiller (plugs, mgr.au_plugin_info ());
2433 refiller (plugs, mgr.ladspa_plugin_info ());
2434 refiller (plugs, mgr.lua_plugin_info ());
2436 store_current_favorite_order ();
2438 PluginCustomSorter cmp (favorite_order);
2441 favorite_order = plugs;
2443 sync_treeview_from_favorite_order ();
2447 Mixer_UI::sync_treeview_favorite_ui_state (const TreeModel::Path& path, const TreeModel::iterator&)
2450 if (!(iter = favorite_plugins_model->get_iter (path))) {
2453 ARDOUR::PluginPresetPtr ppp = (*iter)[favorite_plugins_columns.plugin];
2457 PluginInfoPtr pip = ppp->_pip;
2458 if (favorite_ui_state.find (pip->unique_id) != favorite_ui_state.end ()) {
2459 if (favorite_ui_state[pip->unique_id]) {
2460 favorite_plugins_display.expand_row (path, true);
2466 Mixer_UI::sync_treeview_from_favorite_order ()
2468 favorite_plugins_model->clear ();
2469 for (PluginInfoList::const_iterator i = favorite_order.begin(); i != favorite_order.end(); ++i) {
2470 PluginInfoPtr pip = (*i);
2472 TreeModel::Row newrow = *(favorite_plugins_model->append());
2473 newrow[favorite_plugins_columns.name] = (*i)->name;
2474 newrow[favorite_plugins_columns.plugin] = PluginPresetPtr (new PluginPreset(pip));
2479 vector<ARDOUR::Plugin::PresetRecord> presets = (*i)->get_presets (true);
2480 for (vector<ARDOUR::Plugin::PresetRecord>::const_iterator j = presets.begin(); j != presets.end(); ++j) {
2481 Gtk::TreeModel::Row child_row = *(favorite_plugins_model->append (newrow.children()));
2482 child_row[favorite_plugins_columns.name] = (*j).label;
2483 child_row[favorite_plugins_columns.plugin] = PluginPresetPtr (new PluginPreset(pip, &(*j)));
2485 if (favorite_ui_state.find (pip->unique_id) != favorite_ui_state.end ()) {
2486 if (favorite_ui_state[pip->unique_id]) {
2487 favorite_plugins_display.expand_row (favorite_plugins_model->get_path(newrow), true);
2494 Mixer_UI::popup_note_context_menu (GdkEventButton *ev)
2496 using namespace Gtk::Menu_Helpers;
2498 Gtk::Menu* m = manage (new Menu);
2499 MenuList& items = m->items ();
2501 if (_selection.routes.empty()) {
2502 items.push_back (MenuElem (_("No Track/Bus is selected.")));
2504 items.push_back (MenuElem (_("Add at the top"),
2505 sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddTop)));
2506 items.push_back (MenuElem (_("Add Pre-Fader"),
2507 sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddPreFader)));
2508 items.push_back (MenuElem (_("Add Post-Fader"),
2509 sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddPostFader)));
2510 items.push_back (MenuElem (_("Add at the end"),
2511 sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddBottom)));
2514 items.push_back (SeparatorElem());
2516 items.push_back (MenuElem (_("Remove from favorites"), sigc::mem_fun (*this, &Mixer_UI::remove_selected_from_favorites)));
2518 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2519 if (ppp && ppp->_preset.valid && ppp->_preset.user) {
2520 // we cannot currently delete AU presets
2521 if (!ppp->_pip || ppp->_pip->type != AudioUnit) {
2522 items.push_back (MenuElem (_("Delete Preset"), sigc::mem_fun (*this, &Mixer_UI::delete_selected_preset)));
2526 m->popup (ev->button, ev->time);
2530 Mixer_UI::plugin_row_button_press (GdkEventButton *ev)
2532 if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 3) ) {
2533 TreeModel::Path path;
2534 TreeViewColumn* column;
2536 if (favorite_plugins_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
2537 Glib::RefPtr<Gtk::TreeView::Selection> selection = favorite_plugins_display.get_selection();
2539 selection->unselect_all();
2540 selection->select(path);
2543 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2545 popup_note_context_menu (ev);
2553 Mixer_UI::selected_plugin ()
2555 Glib::RefPtr<Gtk::TreeView::Selection> selection = favorite_plugins_display.get_selection();
2557 return PluginPresetPtr();
2559 Gtk::TreeModel::iterator iter = selection->get_selected();
2561 return PluginPresetPtr();
2563 return (*iter)[favorite_plugins_columns.plugin];
2567 Mixer_UI::add_selected_processor (ProcessorPosition pos)
2569 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2571 add_favorite_processor (ppp, pos);
2576 Mixer_UI::delete_selected_preset ()
2581 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2582 if (!ppp || !ppp->_preset.valid || !ppp->_preset.user) {
2585 PluginPtr plugin = ppp->_pip->load (*_session);
2586 plugin->get_presets();
2587 plugin->remove_preset (ppp->_preset.label);
2591 Mixer_UI::remove_selected_from_favorites ()
2593 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2597 PluginManager::PluginStatusType status = PluginManager::Normal;
2598 PluginManager& manager (PluginManager::instance());
2600 manager.set_status (ppp->_pip->type, ppp->_pip->unique_id, status);
2601 manager.save_statuses ();
2605 Mixer_UI::plugin_row_activated (const TreeModel::Path& path, TreeViewColumn* column)
2608 if (!(iter = favorite_plugins_model->get_iter (path))) {
2611 ARDOUR::PluginPresetPtr ppp = (*iter)[favorite_plugins_columns.plugin];
2612 add_favorite_processor (ppp, AddPreFader); // TODO: preference?!
2616 Mixer_UI::add_favorite_processor (ARDOUR::PluginPresetPtr ppp, ProcessorPosition pos)
2618 if (!_session || _selection.routes.empty()) {
2622 PluginInfoPtr pip = ppp->_pip;
2623 for (RouteUISelection::iterator i = _selection.routes.begin(); i != _selection.routes.end(); ++i) {
2624 boost::shared_ptr<ARDOUR::Route> rt = (*i)->route();
2625 if (!rt) { continue; }
2627 PluginPtr p = pip->load (*_session);
2628 if (!p) { continue; }
2630 if (ppp->_preset.valid) {
2631 p->load_preset (ppp->_preset);
2634 Route::ProcessorStreams err;
2635 boost::shared_ptr<Processor> processor (new PluginInsert (*_session, p));
2639 rt->add_processor_by_index (processor, 0, &err, Config->get_new_plugins_active ());
2642 rt->add_processor (processor, PreFader, &err, Config->get_new_plugins_active ());
2649 boost::shared_ptr<Processor> np = rt->nth_processor (idx);
2653 if (!np->display_to_user()) {
2656 if (boost::dynamic_pointer_cast<Amp> (np) && // Fader, not Trim
2657 boost::dynamic_pointer_cast<Amp> (np)->gain_control()->parameter().type() == GainAutomation) {
2662 rt->add_processor_by_index (processor, ++pos, &err, Config->get_new_plugins_active ());
2666 rt->add_processor_by_index (processor, -1, &err, Config->get_new_plugins_active ());
2673 PluginTreeStore::row_drop_possible_vfunc(const Gtk::TreeModel::Path& dest, const Gtk::SelectionData& data) const
2675 if (data.get_target() != "GTK_TREE_MODEL_ROW") {
2679 // only allow to re-order top-level items
2681 if (TreePath::get_from_selection_data (data, src)) {
2682 if (src.up() && src.up()) {
2687 // don't allow to drop as child-rows.
2688 Gtk::TreeModel::Path _dest = dest; // un const
2689 const bool is_child = _dest.up (); // explicit bool for clang
2690 if (!is_child || _dest.empty ()) {
2697 Mixer_UI::plugin_drop (const Glib::RefPtr<Gdk::DragContext>&, const Gtk::SelectionData& data)
2699 if (data.get_target() != "PluginPresetPtr") {
2702 if (data.get_length() != sizeof (PluginPresetPtr)) {
2705 const void *d = data.get_data();
2706 const PluginPresetPtr ppp = *(static_cast<const PluginPresetPtr*> (d));
2708 PluginManager::PluginStatusType status = PluginManager::Favorite;
2709 PluginManager& manager (PluginManager::instance());
2711 manager.set_status (ppp->_pip->type, ppp->_pip->unique_id, status);
2712 manager.save_statuses ();
2716 Mixer_UI::do_vca_assign (boost::shared_ptr<VCA> vca)
2718 /* call protected MixerActor:: method */
2723 Mixer_UI::do_vca_unassign (boost::shared_ptr<VCA> vca)
2725 /* call protected MixerActor:: method */