remove misc. debug output
[ardour.git] / gtk2_ardour / mixer_ui.cc
1 /*
2     Copyright (C) 2000-2004 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 #include <algorithm>
25 #include <map>
26 #include <sigc++/bind.h>
27
28 #include <boost/foreach.hpp>
29
30 #include <gtkmm/accelmap.h>
31
32 #include "pbd/convert.h"
33 #include "pbd/stacktrace.h"
34 #include "pbd/unwind.h"
35
36 #include <glibmm/threads.h>
37
38 #include <gtkmm2ext/gtk_ui.h>
39 #include <gtkmm2ext/keyboard.h>
40 #include <gtkmm2ext/utils.h>
41 #include <gtkmm2ext/tearoff.h>
42 #include <gtkmm2ext/window_title.h>
43 #include <gtkmm2ext/doi.h>
44
45 #include "ardour/amp.h"
46 #include "ardour/debug.h"
47 #include "ardour/audio_track.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/plugin_manager.h"
50 #include "ardour/route_group.h"
51 #include "ardour/selection.h"
52 #include "ardour/session.h"
53 #include "ardour/vca.h"
54 #include "ardour/vca_manager.h"
55
56 #include "keyboard.h"
57 #include "mixer_ui.h"
58 #include "mixer_strip.h"
59 #include "monitor_section.h"
60 #include "plugin_selector.h"
61 #include "public_editor.h"
62 #include "mouse_cursors.h"
63 #include "ardour_ui.h"
64 #include "prompter.h"
65 #include "utils.h"
66 #include "route_sorter.h"
67 #include "actions.h"
68 #include "gui_thread.h"
69 #include "mixer_group_tabs.h"
70 #include "route_sorter.h"
71 #include "timers.h"
72 #include "ui_config.h"
73 #include "vca_master_strip.h"
74
75 #include "pbd/i18n.h"
76
77 using namespace ARDOUR;
78 using namespace ARDOUR_UI_UTILS;
79 using namespace PBD;
80 using namespace Gtk;
81 using namespace Glib;
82 using namespace Gtkmm2ext;
83 using namespace std;
84
85 using PBD::atoi;
86 using PBD::Unwinder;
87
88 Mixer_UI* Mixer_UI::_instance = 0;
89
90 Mixer_UI*
91 Mixer_UI::instance ()
92 {
93         if (!_instance) {
94                 _instance  = new Mixer_UI;
95         }
96
97         return _instance;
98 }
99
100 Mixer_UI::Mixer_UI ()
101         : Tabbable (_content, _("Mixer"))
102         , no_track_list_redisplay (false)
103         , in_group_row_change (false)
104         , track_menu (0)
105         , _monitor_section (0)
106         , _plugin_selector (0)
107         , _strip_width (UIConfiguration::instance().get_default_narrow_ms() ? Narrow : Wide)
108         , ignore_reorder (false)
109         , _in_group_rebuild_or_clear (false)
110         , _route_deletion_in_progress (false)
111         , _maximised (false)
112         , _show_mixer_list (true)
113         , myactions (X_("mixer"))
114         , _selection (*this, *this)
115 {
116         register_actions ();
117         load_bindings ();
118         _content.set_data ("ardour-bindings", bindings);
119
120         PresentationInfo::Change.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::presentation_info_changed, this, _1), gui_context());
121
122         scroller.set_can_default (true);
123         // set_default (scroller);
124
125         scroller_base.set_flags (Gtk::CAN_FOCUS);
126         scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
127         scroller_base.set_name ("MixerWindow");
128         scroller_base.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::strip_scroller_button_release));
129
130         /* set up drag-n-drop */
131         vector<TargetEntry> target_table;
132         target_table.push_back (TargetEntry ("PluginFavoritePtr"));
133         scroller_base.drag_dest_set (target_table);
134         scroller_base.signal_drag_data_received().connect (sigc::mem_fun(*this, &Mixer_UI::scroller_drag_data_received));
135
136         // add as last item of strip packer
137         strip_packer.pack_end (scroller_base, true, true);
138
139         _group_tabs = new MixerGroupTabs (this);
140         VBox* b = manage (new VBox);
141         b->set_spacing (0);
142         b->set_border_width (0);
143         b->pack_start (*_group_tabs, PACK_SHRINK);
144         b->pack_start (strip_packer);
145         b->show_all ();
146         b->signal_scroll_event().connect (sigc::mem_fun (*this, &Mixer_UI::on_scroll_event), false);
147
148         scroller.add (*b);
149         scroller.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC);
150
151         setup_track_display ();
152
153         group_model = ListStore::create (group_columns);
154         group_display.set_model (group_model);
155         group_display.append_column (_("Show"), group_columns.visible);
156         group_display.append_column (_("Group"), group_columns.text);
157         group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
158         group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
159         group_display.get_column (0)->set_expand(false);
160         group_display.get_column (1)->set_expand(true);
161         group_display.get_column (1)->set_sizing (Gtk::TREE_VIEW_COLUMN_FIXED);
162         group_display.set_name ("EditGroupList");
163         group_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
164         group_display.set_reorderable (true);
165         group_display.set_headers_visible (true);
166         group_display.set_rules_hint (true);
167         group_display.set_can_focus(false);
168
169         /* name is directly editable */
170
171         CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (1));
172         name_cell->property_editable() = true;
173         name_cell->signal_edited().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_name_edit));
174
175         /* use checkbox for the active column */
176
177         CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(group_display.get_column_cell_renderer (0));
178         active_cell->property_activatable() = true;
179         active_cell->property_radio() = false;
180
181         group_model->signal_row_changed().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_change));
182         /* We use this to notice drag-and-drop reorders of the group list */
183         group_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_deleted));
184         group_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::group_display_button_press), false);
185
186         group_display_scroller.add (group_display);
187         group_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
188
189         HBox* route_group_display_button_box = manage (new HBox());
190
191         Button* route_group_add_button = manage (new Button ());
192         Button* route_group_remove_button = manage (new Button ());
193
194         Widget* w;
195
196         w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
197         w->show();
198         route_group_add_button->add (*w);
199
200         w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
201         w->show();
202         route_group_remove_button->add (*w);
203
204         route_group_display_button_box->set_homogeneous (true);
205
206         route_group_add_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_route_group));
207         route_group_remove_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::remove_selected_route_group));
208
209         route_group_display_button_box->add (*route_group_add_button);
210         route_group_display_button_box->add (*route_group_remove_button);
211
212         group_display_vbox.pack_start (group_display_scroller, true, true);
213         group_display_vbox.pack_start (*route_group_display_button_box, false, false);
214
215         group_display_frame.set_name ("BaseFrame");
216         group_display_frame.set_shadow_type (Gtk::SHADOW_IN);
217         group_display_frame.add (group_display_vbox);
218
219
220         list<TargetEntry> target_list;
221         target_list.push_back (TargetEntry ("PluginPresetPtr"));
222
223         favorite_plugins_model = PluginTreeStore::create (favorite_plugins_columns);
224         favorite_plugins_display.set_model (favorite_plugins_model);
225         favorite_plugins_display.append_column (_("Favorite Plugins"), favorite_plugins_columns.name);
226         favorite_plugins_display.set_name ("EditGroupList");
227         favorite_plugins_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
228         favorite_plugins_display.set_reorderable (false);
229         favorite_plugins_display.set_headers_visible (true);
230         favorite_plugins_display.set_rules_hint (true);
231         favorite_plugins_display.set_can_focus (false);
232         favorite_plugins_display.set_tooltip_column (0);
233         favorite_plugins_display.add_object_drag (favorite_plugins_columns.plugin.index(), "PluginFavoritePtr");
234         favorite_plugins_display.set_drag_column (favorite_plugins_columns.name.index());
235         favorite_plugins_display.add_drop_targets (target_list);
236         favorite_plugins_display.signal_row_activated().connect (sigc::mem_fun (*this, &Mixer_UI::plugin_row_activated));
237         favorite_plugins_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::plugin_row_button_press), false);
238         favorite_plugins_display.signal_drop.connect (sigc::mem_fun (*this, &Mixer_UI::plugin_drop));
239         favorite_plugins_display.signal_row_expanded().connect (sigc::mem_fun (*this, &Mixer_UI::save_favorite_ui_state));
240         favorite_plugins_display.signal_row_collapsed().connect (sigc::mem_fun (*this, &Mixer_UI::save_favorite_ui_state));
241         favorite_plugins_model->signal_row_has_child_toggled().connect (sigc::mem_fun (*this, &Mixer_UI::sync_treeview_favorite_ui_state));
242
243         favorite_plugins_scroller.add (favorite_plugins_display);
244         favorite_plugins_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
245
246         favorite_plugins_frame.set_name ("BaseFrame");
247         favorite_plugins_frame.set_shadow_type (Gtk::SHADOW_IN);
248         favorite_plugins_frame.add (favorite_plugins_scroller);
249
250         rhs_pane1.add (favorite_plugins_frame);
251         rhs_pane1.add (track_display_frame);
252
253         rhs_pane2.add (rhs_pane1);
254         rhs_pane2.add (group_display_frame);
255
256         list_vpacker.pack_start (rhs_pane2, true, true);
257
258         vca_label_bar.set_size_request (-1, 16 + 1); /* must match height in GroupTabs::set_size_request()  + 1 border px*/
259         vca_vpacker.pack_start (vca_label_bar, false, false);
260
261         vca_scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
262         vca_scroller_base.set_name (X_("MixerWindow"));
263         vca_scroller_base.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::masters_scroller_button_release), false);
264         vca_hpacker.pack_end (vca_scroller_base, true, true);
265
266         vca_scroller.add (vca_hpacker);
267         vca_scroller.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC);
268         vca_scroller.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::strip_scroller_button_release));
269
270         vca_vpacker.pack_start (vca_scroller, true, true);
271
272         inner_pane.add (scroller);
273         inner_pane.add (vca_vpacker);
274
275         global_hpacker.pack_start (inner_pane, true, true);
276         global_hpacker.pack_start (out_packer, false, false);
277
278         list_hpane.set_check_divider_position (true);
279         list_hpane.add (list_vpacker);
280         list_hpane.add (global_hpacker);
281         list_hpane.set_child_minsize (list_vpacker, 1);
282
283
284         XMLNode const * settings = ARDOUR_UI::instance()->mixer_settings();
285         float fract;
286
287         {
288                 LocaleGuard lg;
289
290                 if (!settings || !settings->get_property ("mixer-rhs-pane1-pos", fract) || fract  > 1.0) {
291                         fract = 0.6f;
292                 }
293                 rhs_pane1.set_divider (0, fract);
294
295                 if (!settings || !settings->get_property ("mixer-rhs-pane2-pos", fract) || fract > 1.0) {
296                         fract = 0.7f;
297                 }
298                 rhs_pane2.set_divider (0, fract);
299
300                 if (!settings || !settings->get_property ("mixer-list-hpane-pos", fract) || fract > 1.0) {
301                         fract = 0.2f;
302                 }
303                 list_hpane.set_divider (0, fract);
304
305                 if (!settings || !settings->get_property ("mixer-inner-pane-pos", fract) || fract > 1.0) {
306                         fract = 0.8f;
307                 }
308                 inner_pane.set_divider (0, fract);
309         }
310
311         rhs_pane1.set_drag_cursor (*PublicEditor::instance().cursors()->expand_up_down);
312         rhs_pane2.set_drag_cursor (*PublicEditor::instance().cursors()->expand_up_down);
313         list_hpane.set_drag_cursor (*PublicEditor::instance().cursors()->expand_left_right);
314         inner_pane.set_drag_cursor (*PublicEditor::instance().cursors()->expand_left_right);
315
316         _content.pack_start (list_hpane, true, true);
317
318         update_title ();
319
320         route_group_display_button_box->show();
321         route_group_add_button->show();
322         route_group_remove_button->show();
323
324         _content.show ();
325         _content.set_name ("MixerWindow");
326
327         global_hpacker.show();
328         scroller.show();
329         scroller_base.show();
330         scroller_hpacker.show();
331         mixer_scroller_vpacker.show();
332         list_vpacker.show();
333         group_display_button_label.show();
334         group_display_button.show();
335         group_display_scroller.show();
336         favorite_plugins_scroller.show();
337         group_display_vbox.show();
338         group_display_frame.show();
339         favorite_plugins_frame.show();
340         rhs_pane1.show();
341         rhs_pane2.show();
342         strip_packer.show();
343         inner_pane.show();
344         vca_scroller.show();
345         vca_vpacker.show();
346         vca_hpacker.show();
347         vca_label_bar.show();
348         vca_label.show();
349         vca_scroller_base.show();
350         out_packer.show();
351         list_hpane.show();
352         group_display.show();
353         favorite_plugins_display.show();
354
355         MixerStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_strip, this, _1), gui_context());
356
357         /* handle escape */
358
359         ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::escape, this), gui_context());
360
361 #ifndef DEFER_PLUGIN_SELECTOR_LOAD
362         _plugin_selector = new PluginSelector (PluginManager::instance ());
363 #else
364 #error implement deferred Plugin-Favorite list
365 #endif
366         PluginManager::instance ().PluginListChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context());
367         PluginManager::instance ().PluginStatusesChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context());
368         ARDOUR::Plugin::PresetsChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context());
369 }
370
371 Mixer_UI::~Mixer_UI ()
372 {
373         if (_monitor_section) {
374                 monitor_section_detached ();
375                 delete _monitor_section;
376         }
377         delete _plugin_selector;
378         delete track_menu;
379 }
380
381 void
382 Mixer_UI::escape ()
383 {
384         select_none ();
385 }
386
387 Gtk::Window*
388 Mixer_UI::use_own_window (bool and_fill_it)
389 {
390         bool new_window = !own_window();
391
392         Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
393
394         if (win && new_window) {
395                 win->set_name ("MixerWindow");
396                 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Mixer"), this);
397                 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
398                 win->set_data ("ardour-bindings", bindings);
399                 update_title ();
400                 if (!win->get_focus()) {
401                         /* set focus widget to something, anything */
402                         win->set_focus (scroller);
403                 }
404         }
405
406         return win;
407 }
408
409 void
410 Mixer_UI::show_window ()
411 {
412         Tabbable::show_window ();
413
414         /* show/hide group tabs as required */
415         parameter_changed ("show-group-tabs");
416
417         /* now reset each strips width so the right widgets are shown */
418
419         TreeModel::Children rows = track_model->children();
420         TreeModel::Children::iterator ri;
421
422         for (ri = rows.begin(); ri != rows.end(); ++ri) {
423                 AxisView* av = (*ri)[stripable_columns.strip];
424                 MixerStrip* ms = dynamic_cast<MixerStrip*> (av);
425                 if (!ms) {
426                         continue;
427                 }
428                 ms->set_width_enum (ms->get_width_enum (), ms->width_owner());
429                 /* Fix visibility of mixer strip stuff */
430                 ms->parameter_changed (X_("mixer-element-visibility"));
431         }
432
433         /* force focus into main area */
434         scroller_base.grab_focus ();
435 }
436
437 void
438 Mixer_UI::remove_master (VCAMasterStrip* vms)
439 {
440         if (_session && _session->deletion_in_progress()) {
441                 /* its all being taken care of */
442                 return;
443         }
444
445         TreeModel::Children rows = track_model->children();
446         TreeModel::Children::iterator ri;
447
448         for (ri = rows.begin(); ri != rows.end(); ++ri) {
449                 if ((*ri)[stripable_columns.strip] == vms) {
450                         PBD::Unwinder<bool> uw (_route_deletion_in_progress, true);
451                         track_model->erase (ri);
452                         break;
453                 }
454         }
455 }
456
457 bool
458 Mixer_UI::masters_scroller_button_release (GdkEventButton* ev)
459 {
460         using namespace Menu_Helpers;
461
462         if (Keyboard::is_context_menu_event (ev)) {
463                 ARDOUR_UI::instance()->add_route ();
464                 return true;
465         }
466
467         return false;
468 }
469
470 void
471 Mixer_UI::add_masters (VCAList& vlist)
472 {
473         StripableList sl;
474
475         for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
476                 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
477         }
478
479         add_stripables (sl);
480 }
481
482 void
483 Mixer_UI::add_routes (RouteList& rlist)
484 {
485         StripableList sl;
486
487         for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
488                 sl.push_back (*r);
489         }
490
491         add_stripables (sl);
492 }
493
494 void
495 Mixer_UI::add_stripables (StripableList& slist)
496 {
497         Gtk::TreeModel::Children::iterator insert_iter = track_model->children().end();
498         bool from_scratch = (track_model->children().size() == 0);
499         uint32_t nroutes = 0;
500
501         slist.sort (StripablePresentationInfoSorter());
502
503         for (Gtk::TreeModel::Children::iterator it = track_model->children().begin(); it != track_model->children().end(); ++it) {
504                 boost::shared_ptr<Stripable> s = (*it)[stripable_columns.stripable];
505
506                 if (!s) {
507                         continue;
508                 }
509
510                 nroutes++;
511
512                 if (s->presentation_info().order() == (slist.front()->presentation_info().order() + slist.size())) {
513                         insert_iter = it;
514                         break;
515                 }
516         }
517
518         MixerStrip* strip;
519
520         try {
521                 PBD::Unwinder<bool> uw (no_track_list_redisplay, true);
522
523                 track_display.set_model (Glib::RefPtr<ListStore>());
524
525                 for (StripableList::iterator s = slist.begin(); s != slist.end(); ++s) {
526
527                         boost::shared_ptr<Route> route;
528                         boost::shared_ptr<VCA> vca;
529
530                         if ((vca  = boost::dynamic_pointer_cast<VCA> (*s))) {
531
532                                 VCAMasterStrip* vms = new VCAMasterStrip (_session, vca);
533
534                                 TreeModel::Row row = *(track_model->append());
535
536                                 row[stripable_columns.text] = vca->name();
537                                 row[stripable_columns.visible] = vms->marked_for_display ();
538                                 row[stripable_columns.strip] = vms;
539                                 row[stripable_columns.stripable] = vca;
540
541                                 vms->CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_master, this, _1), gui_context());
542
543                         } else if ((route = boost::dynamic_pointer_cast<Route> (*s))) {
544
545                                 if (route->is_auditioner()) {
546                                         continue;
547                                 }
548
549                                 if (route->is_monitor()) {
550
551                                         if (!_monitor_section) {
552                                                 _monitor_section = new MonitorSection (_session);
553
554                                                 XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
555                                                 if (mnode) {
556                                                         _monitor_section->tearoff().set_state (*mnode);
557                                                 }
558                                         }
559
560                                         out_packer.pack_end (_monitor_section->tearoff(), false, false);
561                                         _monitor_section->set_session (_session);
562                                         _monitor_section->tearoff().show_all ();
563
564                                         _monitor_section->tearoff().Detach.connect (sigc::mem_fun(*this, &Mixer_UI::monitor_section_detached));
565                                         _monitor_section->tearoff().Attach.connect (sigc::mem_fun(*this, &Mixer_UI::monitor_section_attached));
566
567                                         monitor_section_attached ();
568
569                                         route->DropReferences.connect (*this, invalidator(*this), boost::bind (&Mixer_UI::monitor_section_going_away, this), gui_context());
570
571                                         /* no regular strip shown for control out */
572
573                                         continue;
574                                 }
575
576                                 strip = new MixerStrip (*this, _session, route);
577                                 strips.push_back (strip);
578
579                                 UIConfiguration::instance().get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide;
580
581                                 if (strip->width_owner() != strip) {
582                                         strip->set_width_enum (_strip_width, this);
583                                 }
584
585                                 show_strip (strip);
586
587                                 if (!route->is_master()) {
588
589                                         TreeModel::Row row = *(track_model->insert (insert_iter));
590
591                                         row[stripable_columns.text] = route->name();
592                                         row[stripable_columns.visible] = strip->marked_for_display();
593                                         row[stripable_columns.stripable] = route;
594                                         row[stripable_columns.strip] = strip;
595
596                                 } else {
597
598                                         out_packer.pack_start (*strip, false, false);
599                                         strip->set_packed (true);
600                                 }
601
602                                 strip->WidthChanged.connect (sigc::mem_fun(*this, &Mixer_UI::strip_width_changed));
603                                 strip->signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::strip_button_release_event), strip));
604                         }
605
606                         (*s)->presentation_info().PropertyChanged.connect (*this, invalidator(*this), boost::bind (&Mixer_UI::stripable_property_changed, this, _1, boost::weak_ptr<Stripable>(*s)), gui_context());
607                         (*s)->PropertyChanged.connect (*this, invalidator(*this), boost::bind (&Mixer_UI::stripable_property_changed, this, _1, boost::weak_ptr<Stripable>(*s)), gui_context());
608                 }
609
610         } catch (const std::exception& e) {
611                 error << string_compose (_("Error adding GUI elements for new tracks/busses %1"), e.what()) << endmsg;
612         }
613
614         track_display.set_model (track_model);
615
616         /* catch up on selection state, which we left to the editor to set */
617         sync_treeview_from_presentation_info (PropertyChange (Properties::selected));
618
619         if (!from_scratch) {
620                 sync_presentation_info_from_treeview ();
621         }
622
623         redisplay_track_list ();
624 }
625
626 void
627 Mixer_UI::deselect_all_strip_processors ()
628 {
629         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
630                 (*i)->deselect_all_processors();
631         }
632 }
633
634 void
635 Mixer_UI::select_strip (MixerStrip& ms, bool add)
636 {
637         if (add) {
638                 _selection.add (&ms);
639         } else {
640                 _selection.set (&ms);
641         }
642 }
643
644 void
645 Mixer_UI::select_none ()
646 {
647         _selection.clear_routes();
648         deselect_all_strip_processors();
649 }
650
651 void
652 Mixer_UI::delete_processors ()
653 {
654         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
655                 (*i)->delete_processors();
656         }
657 }
658
659
660 void
661 Mixer_UI::remove_strip (MixerStrip* strip)
662 {
663         if (_session && _session->deletion_in_progress()) {
664                 /* its all being taken care of */
665                 return;
666         }
667
668         TreeModel::Children rows = track_model->children();
669         TreeModel::Children::iterator ri;
670         list<MixerStrip *>::iterator i;
671
672         if ((i = find (strips.begin(), strips.end(), strip)) != strips.end()) {
673                 strips.erase (i);
674         }
675
676         PBD::Unwinder<bool> uwi (ignore_reorder, true);
677
678         for (ri = rows.begin(); ri != rows.end(); ++ri) {
679                 if ((*ri)[stripable_columns.strip] == strip) {
680                         PBD::Unwinder<bool> uw (_route_deletion_in_progress, true);
681                         track_model->erase (ri);
682                         break;
683                 }
684         }
685 }
686
687 void
688 Mixer_UI::presentation_info_changed (PropertyChange const & what_changed)
689 {
690         if (what_changed.contains (Properties::selected)) {
691                 _selection.presentation_info_changed (what_changed);
692         }
693
694         PropertyChange soh;
695         soh.add (Properties::selected);
696         soh.add (Properties::order);
697         soh.add (Properties::hidden);
698
699         if (what_changed.contains (soh)) {
700                 sync_treeview_from_presentation_info (what_changed);
701         }
702 }
703
704 void
705 Mixer_UI::sync_presentation_info_from_treeview ()
706 {
707         if (ignore_reorder || !_session || _session->deletion_in_progress()) {
708                 return;
709         }
710
711         TreeModel::Children rows = track_model->children();
712
713         if (rows.empty()) {
714                 return;
715         }
716
717         DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync presentation info from treeview\n");
718
719         TreeModel::Children::iterator ri;
720         bool change = false;
721         uint32_t order = 0;
722
723         OrderingKeys sorted;
724         const size_t cmp_max = rows.size ();
725
726         // special case master if it's got PI order 0 lets keep it there
727         if (_session->master_out() && (_session->master_out()->presentation_info().order() == 0)) {
728                 order++;
729         }
730
731         PresentationInfo::ChangeSuspender cs;
732
733         for (ri = rows.begin(); ri != rows.end(); ++ri) {
734                 bool visible = (*ri)[stripable_columns.visible];
735                 boost::shared_ptr<Stripable> stripable = (*ri)[stripable_columns.stripable];
736
737                 if (!stripable) {
738                         continue;
739                 }
740
741                 /* Monitor and Auditioner do not get their presentation
742                  * info reset here.
743                  */
744
745                 if (stripable->is_monitor() || stripable->is_auditioner()) {
746                         continue;
747                 }
748
749                 /* Master also doesn't get set here but since the editor allows
750                  * it to be reordered, we need to preserve its ordering.
751                  */
752
753                 stripable->presentation_info().set_hidden (!visible);
754
755                 // master may not get set here, but if it is zero keep it there
756                 if (stripable->is_master() && (stripable->presentation_info().order() == 0)) {
757                         continue;
758                 }
759
760                 if (order != stripable->presentation_info().order()) {
761                         stripable->set_presentation_order (order);
762                         change = true;
763                 }
764
765                 sorted.push_back (OrderKeys (order, stripable, cmp_max));
766
767                 ++order;
768         }
769
770         if (!change) {
771                 // VCA (and Mixbus) special cases according to SortByNewDisplayOrder
772                 uint32_t n = 0;
773                 SortByNewDisplayOrder cmp;
774                 sort (sorted.begin(), sorted.end(), cmp);
775                 for (OrderingKeys::iterator sr = sorted.begin(); sr != sorted.end(); ++sr, ++n) {
776                         if (_session->master_out() && (_session->master_out()->presentation_info().order() == n)) {
777                                 ++n;
778                         }
779                         if (sr->old_display_order != n) {
780                                 change = true;
781                                 break;
782                         }
783                 }
784                 if (change) {
785                         n = 0;
786                         for (OrderingKeys::iterator sr = sorted.begin(); sr != sorted.end(); ++sr, ++n) {
787                                 if (_session->master_out() && (_session->master_out()->presentation_info().order() == n)) {
788                                         ++n;
789                                 }
790                                 if (sr->stripable->presentation_info().order() != n) {
791                                         sr->stripable->set_presentation_order (n);
792                                 }
793                         }
794                 }
795         }
796
797         if (change) {
798                 DEBUG_TRACE (DEBUG::OrderKeys, "... notify PI change from mixer GUI\n");
799                 _session->set_dirty();
800         }
801 }
802
803 void
804 Mixer_UI::sync_treeview_from_presentation_info (PropertyChange const & what_changed)
805 {
806         if (!_session || _session->deletion_in_progress()) {
807                 return;
808         }
809
810         DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync model from presentation info.\n");
811
812         /* we could get here after either a change in the Mixer or Editor sort
813          * order, but either way, the mixer order keys reflect the intended
814          * order for the GUI, so reorder the treeview model to match it.
815          */
816
817         vector<int> neworder;
818         TreeModel::Children rows = track_model->children();
819         uint32_t old_order = 0;
820         bool changed = false;
821
822         if (rows.empty()) {
823                 return;
824         }
825
826         OrderingKeys sorted;
827         const size_t cmp_max = rows.size ();
828
829         for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
830                 boost::shared_ptr<Stripable> stripable = (*ri)[stripable_columns.stripable];
831                 sorted.push_back (OrderKeys (old_order, stripable, cmp_max));
832         }
833
834         SortByNewDisplayOrder cmp;
835
836         sort (sorted.begin(), sorted.end(), cmp);
837         neworder.assign (sorted.size(), 0);
838
839         uint32_t n = 0;
840
841         for (OrderingKeys::iterator sr = sorted.begin(); sr != sorted.end(); ++sr, ++n) {
842
843                 neworder[n] = sr->old_display_order;
844
845                 if (sr->old_display_order != n) {
846                         changed = true;
847                 }
848         }
849
850         if (changed) {
851                 Unwinder<bool> uw (ignore_reorder, true);
852                 track_model->reorder (neworder);
853         }
854
855         if (what_changed.contains (Properties::selected)) {
856
857                 PresentationInfo::ChangeSuspender cs;
858
859                 for (list<MixerStrip *>::const_iterator i = strips.begin(); i != strips.end(); ++i) {
860                         boost::shared_ptr<Stripable> stripable = (*i)->stripable();
861                         if (stripable && stripable->is_selected()) {
862                                 _selection.add (*i);
863                         } else {
864                                 _selection.remove (*i);
865                         }
866                 }
867
868                 if (!_selection.axes.empty() && !PublicEditor::instance().track_selection_change_without_scroll ()) {
869                         move_stripable_into_view ((*_selection.axes.begin())->stripable());
870                 }
871         }
872
873         redisplay_track_list ();
874 }
875
876
877 MixerStrip*
878 Mixer_UI::strip_by_route (boost::shared_ptr<Route> r) const
879 {
880         for (list<MixerStrip *>::const_iterator i = strips.begin(); i != strips.end(); ++i) {
881                 if ((*i)->route() == r) {
882                         return (*i);
883                 }
884         }
885
886         return 0;
887 }
888
889 MixerStrip*
890 Mixer_UI::strip_by_stripable (boost::shared_ptr<Stripable> s) const
891 {
892         for (list<MixerStrip *>::const_iterator i = strips.begin(); i != strips.end(); ++i) {
893                 if ((*i)->stripable() == s) {
894                         return (*i);
895                 }
896         }
897
898         return 0;
899 }
900
901 AxisView*
902 Mixer_UI::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
903 {
904         for (list<MixerStrip *>::const_iterator i = strips.begin(); i != strips.end(); ++i) {
905                 if ((*i)->stripable() == s) {
906                         return (*i);
907                 }
908         }
909
910         return 0;
911 }
912
913 AxisView*
914 Mixer_UI::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
915 {
916         for (list<MixerStrip *>::const_iterator i = strips.begin(); i != strips.end(); ++i) {
917                 if ((*i)->control() == c) {
918                         return (*i);
919                 }
920         }
921
922         return 0;
923 }
924
925 bool
926 Mixer_UI::strip_button_release_event (GdkEventButton *ev, MixerStrip *strip)
927 {
928         if (ev->button == 1) {
929                 if (_selection.selected (strip)) {
930                         /* primary-click: toggle selection state of strip */
931                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
932                                 _selection.remove (strip);
933                         } else if (_selection.axes.size() > 1) {
934                                 /* de-select others */
935                                 _selection.set (strip);
936                         }
937                 } else {
938                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
939                                 _selection.add (strip);
940                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::RangeSelectModifier)) {
941
942                                 /* extend selection */
943
944                                 vector<MixerStrip*> tmp;
945                                 bool accumulate = false;
946                                 bool found_another = false;
947
948                                 OrderingKeys sorted;
949                                 const size_t cmp_max = strips.size ();
950                                 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
951                                         sorted.push_back (OrderKeys (-1, (*i)->stripable(), cmp_max));
952                                 }
953                                 SortByNewDisplayOrder cmp;
954                                 sort (sorted.begin(), sorted.end(), cmp);
955
956                                 for (OrderingKeys::iterator sr = sorted.begin(); sr != sorted.end(); ++sr) {
957                                         MixerStrip* ms = strip_by_stripable (sr->stripable);
958                                         assert (ms);
959
960                                         if (ms == strip) {
961                                                 /* hit clicked strip, start accumulating till we hit the first
962                                                    selected strip
963                                                 */
964                                                 if (accumulate) {
965                                                         /* done */
966                                                         break;
967                                                 } else {
968                                                         accumulate = true;
969                                                 }
970                                         } else if (_selection.selected (ms)) {
971                                                 /* hit selected strip. if currently accumulating others,
972                                                    we're done. if not accumulating others, start doing so.
973                                                 */
974                                                 found_another = true;
975                                                 if (accumulate) {
976                                                         /* done */
977                                                         break;
978                                                 } else {
979                                                         accumulate = true;
980                                                 }
981                                         } else {
982                                                 if (accumulate) {
983                                                         tmp.push_back (ms);
984                                                 }
985                                         }
986                                 }
987
988                                 tmp.push_back (strip);
989
990                                 if (found_another) {
991                                         PresentationInfo::ChangeSuspender cs;
992                                         for (vector<MixerStrip*>::iterator i = tmp.begin(); i != tmp.end(); ++i) {
993                                                 _selection.add (*i);
994                                         }
995                                 } else {
996                                         _selection.set (strip);  //user wants to start a range selection, but there aren't any others selected yet
997                                 }
998                         } else {
999                                 _selection.set (strip);
1000                         }
1001                 }
1002         }
1003
1004         return true;
1005 }
1006
1007 void
1008 Mixer_UI::set_session (Session* sess)
1009 {
1010         SessionHandlePtr::set_session (sess);
1011
1012         if (_plugin_selector) {
1013                 _plugin_selector->set_session (_session);
1014         }
1015
1016         _group_tabs->set_session (sess);
1017
1018         if (_monitor_section) {
1019                 _monitor_section->set_session (_session);
1020         }
1021
1022         if (!_session) {
1023                 _selection.clear ();
1024                 return;
1025         }
1026
1027         refill_favorite_plugins();
1028
1029         XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
1030         set_state (*node, 0);
1031
1032         update_title ();
1033
1034         initial_track_display ();
1035
1036         _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_routes, this, _1), gui_context());
1037         _session->route_group_added.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_route_group, this, _1), gui_context());
1038         _session->route_group_removed.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
1039         _session->route_groups_reordered.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
1040         _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::parameter_changed, this, _1), gui_context());
1041         _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::update_title, this), gui_context());
1042         _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::update_title, this), gui_context());
1043
1044         _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_masters, this, _1), gui_context());
1045
1046         Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::parameter_changed, this, _1), gui_context ());
1047
1048         route_groups_changed ();
1049
1050         if (_visible) {
1051                 show_window();
1052         }
1053
1054         /* catch up on selection state, etc. */
1055
1056         PropertyChange sc;
1057         sc.add (Properties::selected);
1058         _selection.presentation_info_changed (sc);
1059
1060         start_updating ();
1061 }
1062
1063 void
1064 Mixer_UI::session_going_away ()
1065 {
1066         ENSURE_GUI_THREAD (*this, &Mixer_UI::session_going_away);
1067
1068         _in_group_rebuild_or_clear = true;
1069         group_model->clear ();
1070         _in_group_rebuild_or_clear = false;
1071
1072         _selection.clear ();
1073         track_model->clear ();
1074
1075         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1076                 delete (*i);
1077         }
1078
1079         if (_monitor_section) {
1080                 _monitor_section->tearoff().hide_visible ();
1081         }
1082
1083         monitor_section_detached ();
1084
1085         strips.clear ();
1086
1087         stop_updating ();
1088
1089         SessionHandlePtr::session_going_away ();
1090
1091         _session = 0;
1092         update_title ();
1093 }
1094
1095 void
1096 Mixer_UI::track_visibility_changed (std::string const & path)
1097 {
1098         if (_session && _session->deletion_in_progress()) {
1099                 return;
1100         }
1101
1102         TreeIter iter;
1103
1104         if ((iter = track_model->get_iter (path))) {
1105
1106                 AxisView* av = (*iter)[stripable_columns.strip];
1107                 bool visible = (*iter)[stripable_columns.visible];
1108
1109                 if (av->set_marked_for_display (!visible)) {
1110                         update_track_visibility ();
1111                 }
1112         }
1113 }
1114
1115 void
1116 Mixer_UI::update_track_visibility ()
1117 {
1118         TreeModel::Children rows = track_model->children();
1119         TreeModel::Children::iterator i;
1120
1121         {
1122                 Unwinder<bool> uw (no_track_list_redisplay, true);
1123
1124                 for (i = rows.begin(); i != rows.end(); ++i) {
1125                         AxisView* av = (*i)[stripable_columns.strip];
1126                         (*i)[stripable_columns.visible] = av->marked_for_display ();
1127                 }
1128
1129                 /* force presentation catch up with visibility changes
1130                  */
1131
1132                 sync_presentation_info_from_treeview ();
1133         }
1134
1135         redisplay_track_list ();
1136 }
1137
1138 void
1139 Mixer_UI::show_strip (MixerStrip* ms)
1140 {
1141         TreeModel::Children rows = track_model->children();
1142         TreeModel::Children::iterator i;
1143
1144         for (i = rows.begin(); i != rows.end(); ++i) {
1145
1146                 AxisView* av = (*i)[stripable_columns.strip];
1147                 MixerStrip* strip = dynamic_cast<MixerStrip*> (av);
1148                 if (strip == ms) {
1149                         (*i)[stripable_columns.visible] = true;
1150                         av->set_marked_for_display (true);
1151                         update_track_visibility ();
1152                         break;
1153                 }
1154         }
1155 }
1156
1157 void
1158 Mixer_UI::hide_strip (MixerStrip* ms)
1159 {
1160         TreeModel::Children rows = track_model->children();
1161         TreeModel::Children::iterator i;
1162
1163         for (i = rows.begin(); i != rows.end(); ++i) {
1164
1165                 AxisView* av = (*i)[stripable_columns.strip];
1166                 MixerStrip* strip = dynamic_cast<MixerStrip*> (av);
1167                 if (strip == ms) {
1168                         (*i)[stripable_columns.visible] = false;
1169                         av->set_marked_for_display (false);
1170                         update_track_visibility ();
1171                         break;
1172                 }
1173         }
1174 }
1175
1176 gint
1177 Mixer_UI::start_updating ()
1178 {
1179     fast_screen_update_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &Mixer_UI::fast_update_strips));
1180     return 0;
1181 }
1182
1183 gint
1184 Mixer_UI::stop_updating ()
1185 {
1186     fast_screen_update_connection.disconnect();
1187     return 0;
1188 }
1189
1190 void
1191 Mixer_UI::fast_update_strips ()
1192 {
1193         if (_content.is_mapped () && _session) {
1194                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1195                         (*i)->fast_update ();
1196                 }
1197         }
1198 }
1199
1200 void
1201 Mixer_UI::set_all_strips_visibility (bool yn)
1202 {
1203         TreeModel::Children rows = track_model->children();
1204         TreeModel::Children::iterator i;
1205
1206         {
1207                 Unwinder<bool> uw (no_track_list_redisplay, true);
1208
1209                 for (i = rows.begin(); i != rows.end(); ++i) {
1210
1211                         AxisView* av = (*i)[stripable_columns.strip];
1212                         MixerStrip* strip = dynamic_cast<MixerStrip*> (av);
1213
1214                         if (!strip) {
1215                                 continue;
1216                         }
1217
1218                         if (strip->route()->is_master() || strip->route()->is_monitor()) {
1219                                 continue;
1220                         }
1221
1222                         (*i)[stripable_columns.visible] = yn;
1223                 }
1224         }
1225
1226         redisplay_track_list ();
1227 }
1228
1229
1230 void
1231 Mixer_UI::set_all_audio_midi_visibility (int tracks, bool yn)
1232 {
1233         TreeModel::Children rows = track_model->children();
1234         TreeModel::Children::iterator i;
1235
1236         {
1237                 Unwinder<bool> uw (no_track_list_redisplay, true);
1238
1239                 for (i = rows.begin(); i != rows.end(); ++i) {
1240
1241                         AxisView* av = (*i)[stripable_columns.strip];
1242                         MixerStrip* strip = dynamic_cast<MixerStrip*> (av);
1243
1244                         if (!strip) {
1245                                 continue;
1246                         }
1247
1248                         if (strip->route()->is_master() || strip->route()->is_monitor()) {
1249                                 continue;
1250                         }
1251
1252                         boost::shared_ptr<AudioTrack> at = strip->audio_track();
1253                         boost::shared_ptr<MidiTrack> mt = strip->midi_track();
1254
1255                         switch (tracks) {
1256                         case 0:
1257                                 (*i)[stripable_columns.visible] = yn;
1258                                 break;
1259
1260                         case 1:
1261                                 if (at) { /* track */
1262                                         (*i)[stripable_columns.visible] = yn;
1263                                 }
1264                                 break;
1265
1266                         case 2:
1267                                 if (!at && !mt) { /* bus */
1268                                         (*i)[stripable_columns.visible] = yn;
1269                                 }
1270                                 break;
1271
1272                         case 3:
1273                                 if (mt) { /* midi-track */
1274                                         (*i)[stripable_columns.visible] = yn;
1275                                 }
1276                                 break;
1277                         }
1278                 }
1279         }
1280
1281         redisplay_track_list ();
1282 }
1283
1284 void
1285 Mixer_UI::hide_all_routes ()
1286 {
1287         set_all_strips_visibility (false);
1288 }
1289
1290 void
1291 Mixer_UI::show_all_routes ()
1292 {
1293         set_all_strips_visibility (true);
1294 }
1295
1296 void
1297 Mixer_UI::show_all_audiobus ()
1298 {
1299         set_all_audio_midi_visibility (2, true);
1300 }
1301 void
1302 Mixer_UI::hide_all_audiobus ()
1303 {
1304         set_all_audio_midi_visibility (2, false);
1305 }
1306
1307 void
1308 Mixer_UI::show_all_audiotracks()
1309 {
1310         set_all_audio_midi_visibility (1, true);
1311 }
1312 void
1313 Mixer_UI::hide_all_audiotracks ()
1314 {
1315         set_all_audio_midi_visibility (1, false);
1316 }
1317
1318 void
1319 Mixer_UI::show_all_miditracks()
1320 {
1321         set_all_audio_midi_visibility (3, true);
1322 }
1323 void
1324 Mixer_UI::hide_all_miditracks ()
1325 {
1326         set_all_audio_midi_visibility (3, false);
1327 }
1328
1329 void
1330 Mixer_UI::track_list_reorder (const TreeModel::Path&, const TreeModel::iterator&, int* /*new_order*/)
1331 {
1332         DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview reordered\n");
1333         sync_presentation_info_from_treeview ();
1334 }
1335
1336 void
1337 Mixer_UI::track_list_delete (const Gtk::TreeModel::Path&)
1338 {
1339         /* this happens as the second step of a DnD within the treeview as well
1340            as when a row/route is actually deleted.
1341
1342            if it was a deletion then we have to force a redisplay because
1343            order keys may not have changed.
1344         */
1345
1346         DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview row deleted\n");
1347         sync_presentation_info_from_treeview ();
1348
1349         if (_route_deletion_in_progress) {
1350                 redisplay_track_list ();
1351         }
1352 }
1353
1354 void
1355 Mixer_UI::spill_redisplay (boost::shared_ptr<VCA> vca)
1356 {
1357         TreeModel::Children rows = track_model->children();
1358         std::list<boost::shared_ptr<VCA> > vcas;
1359         vcas.push_back (vca);
1360
1361         for (TreeModel::Children::const_iterator i = rows.begin(); i != rows.end(); ++i) {
1362                 AxisView* av = (*i)[stripable_columns.strip];
1363                 VCAMasterStrip* vms = dynamic_cast<VCAMasterStrip*> (av);
1364                 if (vms && vms->vca()->slaved_to (vca)) {
1365                         vcas.push_back (vms->vca());
1366                 }
1367         }
1368
1369         for (TreeModel::Children::const_iterator i = rows.begin(); i != rows.end(); ++i) {
1370
1371                 AxisView* av = (*i)[stripable_columns.strip];
1372                 MixerStrip* strip = dynamic_cast<MixerStrip*> (av);
1373                 bool const visible = (*i)[stripable_columns.visible];
1374
1375                 if (!strip) {
1376                         /* we're in the middle of changing a row, don't worry */
1377                         continue;
1378                 }
1379
1380                 if (!strip->route()) {
1381                         /* non-route element */
1382                         continue;
1383                 }
1384
1385                 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1386                         continue;
1387                 }
1388
1389                 bool slaved = false;
1390                 for (std::list<boost::shared_ptr<VCA> >::const_iterator m = vcas.begin(); m != vcas.end(); ++m) {
1391                         if (strip->route()->slaved_to (*m)) {
1392                                 slaved = true;
1393                                 break;
1394                         }
1395                 }
1396
1397                 if (slaved && visible) {
1398
1399                         if (strip->packed()) {
1400                                 strip_packer.reorder_child (*strip, -1); /* put at end */
1401                         } else {
1402                                 strip_packer.pack_start (*strip, false, false);
1403                                 strip->set_packed (true);
1404                         }
1405
1406                 } else {
1407
1408                         if (strip->packed()) {
1409                                 strip_packer.remove (*strip);
1410                                 strip->set_packed (false);
1411                         }
1412                 }
1413         }
1414 }
1415
1416 void
1417 Mixer_UI::redisplay_track_list ()
1418 {
1419         if (no_track_list_redisplay) {
1420                 return;
1421         }
1422
1423         boost::shared_ptr<Stripable> ss = spilled_strip.lock ();
1424         if (ss) {
1425                 boost::shared_ptr<VCA> sv = boost::dynamic_pointer_cast<VCA> (ss);
1426                 if (sv) {
1427                         spill_redisplay (sv);
1428                         return;
1429                 }
1430         }
1431
1432         TreeModel::Children rows = track_model->children();
1433         TreeModel::Children::iterator i;
1434         uint32_t n_masters = 0;
1435
1436         container_clear (vca_hpacker);
1437         vca_hpacker.pack_end (vca_scroller_base, true, true);
1438
1439         for (i = rows.begin(); i != rows.end(); ++i) {
1440
1441                 AxisView* s = (*i)[stripable_columns.strip];
1442                 bool const visible = (*i)[stripable_columns.visible];
1443                 boost::shared_ptr<Stripable> stripable = (*i)[stripable_columns.stripable];
1444
1445                 if (!s) {
1446                         /* we're in the middle of changing a row, don't worry */
1447                         continue;
1448                 }
1449
1450                 VCAMasterStrip* vms;
1451
1452                 if ((vms = dynamic_cast<VCAMasterStrip*> (s))) {
1453                         if (visible) {
1454                                 vca_hpacker.pack_start (*vms, false, false);
1455                                 vms->show ();
1456                                 n_masters++;
1457                         }
1458                         continue;
1459                 }
1460
1461                 MixerStrip* strip = dynamic_cast<MixerStrip*> (s);
1462
1463                 if (!strip) {
1464                         continue;
1465                 }
1466
1467                 if (visible) {
1468
1469                         if (strip->packed()) {
1470                                 strip_packer.reorder_child (*strip, -1); /* put at end */
1471                         } else {
1472                                 strip_packer.pack_start (*strip, false, false);
1473                                 strip->set_packed (true);
1474                         }
1475
1476                 } else {
1477
1478                         if (stripable->is_master() || stripable->is_monitor()) {
1479                                 /* do nothing, these cannot be hidden */
1480                         } else {
1481                                 if (strip->packed()) {
1482                                         strip_packer.remove (*strip);
1483                                         strip->set_packed (false);
1484                                 }
1485                         }
1486                 }
1487         }
1488
1489         /* update visibility of VCA assign buttons */
1490
1491         if (n_masters == 0) {
1492                 UIConfiguration::instance().set_mixer_strip_visibility (VisibilityGroup::remove_element (UIConfiguration::instance().get_mixer_strip_visibility(), X_("VCA")));
1493                 vca_vpacker.hide ();
1494         } else {
1495                 UIConfiguration::instance().set_mixer_strip_visibility (VisibilityGroup::add_element (UIConfiguration::instance().get_mixer_strip_visibility(), X_("VCA")));
1496                 vca_vpacker.show ();
1497         }
1498
1499         _group_tabs->set_dirty ();
1500 }
1501
1502 void
1503 Mixer_UI::strip_width_changed ()
1504 {
1505         _group_tabs->set_dirty ();
1506
1507 #ifdef __APPLE__
1508         TreeModel::Children rows = track_model->children();
1509         TreeModel::Children::iterator i;
1510         long order;
1511
1512         for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
1513                 AxisView* av = (*i)[stripable_columns.strip];
1514                 MixerStrip* strip = dynamic_cast<MixerStrip*> (av);
1515
1516                 if (strip == 0) {
1517                         continue;
1518                 }
1519
1520                 bool visible = (*i)[stripable_columns.visible];
1521
1522                 if (visible) {
1523                         strip->queue_draw();
1524                 }
1525         }
1526 #endif
1527
1528 }
1529
1530 struct PresentationInfoMixerSorter
1531 {
1532         bool operator() (boost::shared_ptr<Stripable> a, boost::shared_ptr<Stripable> b) {
1533                 if (a->is_master()) {
1534                         /* master after everything else */
1535                         return false;
1536                 } else if (b->is_master()) {
1537                         /* everything else before master */
1538                         return true;
1539                 }
1540                 return a->presentation_info().order () < b->presentation_info().order ();
1541         }
1542 };
1543
1544 void
1545 Mixer_UI::initial_track_display ()
1546 {
1547         StripableList sl;
1548
1549         boost::shared_ptr<RouteList> routes = _session->get_routes();
1550
1551         for (RouteList::iterator r = routes->begin(); r != routes->end(); ++r) {
1552                 sl.push_back (*r);
1553         }
1554
1555         VCAList vcas = _session->vca_manager().vcas();
1556
1557         for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
1558                 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
1559         }
1560
1561         sl.sort (PresentationInfoMixerSorter());
1562
1563         {
1564                 /* These are also used inside ::add_stripables() but we need
1565                  *  them here because we're going to clear the track_model also.
1566                  */
1567                 Unwinder<bool> uw1 (no_track_list_redisplay, true);
1568                 Unwinder<bool> uw2 (ignore_reorder, true);
1569
1570                 track_model->clear ();
1571                 add_stripables (sl);
1572         }
1573
1574         sync_treeview_from_presentation_info (Properties::order);
1575 }
1576
1577 bool
1578 Mixer_UI::track_display_button_press (GdkEventButton* ev)
1579 {
1580         if (Keyboard::is_context_menu_event (ev)) {
1581                 if (track_menu == 0) {
1582                         build_track_menu ();
1583                 }
1584                 track_menu->popup (ev->button, ev->time);
1585                 return true;
1586         }
1587         if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 1)) {
1588                 TreeModel::Path path;
1589                 TreeViewColumn* column;
1590                 int cellx, celly;
1591                 if (track_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
1592                         TreeIter iter = track_model->get_iter (path);
1593                         if ((*iter)[stripable_columns.visible]) {
1594                                 boost::shared_ptr<ARDOUR::Stripable> s = (*iter)[stripable_columns.stripable];
1595                                 move_stripable_into_view (s);
1596                         }
1597                 }
1598         }
1599
1600         return false;
1601 }
1602
1603 void
1604 Mixer_UI::move_stripable_into_view (boost::shared_ptr<ARDOUR::Stripable> s)
1605 {
1606         if (!scroller.get_hscrollbar()) {
1607                 return;
1608         }
1609         if (s->presentation_info().special () || s->presentation_info().flag_match (PresentationInfo::VCA)) {
1610                 return;
1611         }
1612 #ifdef MIXBUS
1613         if (s->mixbus ()) {
1614                 return;
1615         }
1616 #endif
1617         bool found = false;
1618         int x0 = 0;
1619         Gtk::Allocation alloc;
1620         for (list<MixerStrip *>::const_iterator i = strips.begin(); i != strips.end(); ++i) {
1621                 if ((*i)->route() == s) {
1622                         int y;
1623                         found = true;
1624                         (*i)->translate_coordinates (strip_packer, 0, 0, x0, y);
1625                         alloc = (*i)->get_allocation ();
1626                         break;
1627                 }
1628         }
1629         if (!found) {
1630                 return;
1631         }
1632
1633         Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1634
1635         if (x0 < adj->get_value()) {
1636                 adj->set_value (max (adj->get_lower(), min (adj->get_upper(), (double) x0)));
1637         } else if (x0 + alloc.get_width() >= adj->get_value() + adj->get_page_size()) {
1638                 int x1 = x0 + alloc.get_width() - adj->get_page_size();
1639                 adj->set_value (max (adj->get_lower(), min (adj->get_upper(), (double) x1)));
1640         }
1641 }
1642
1643 void
1644 Mixer_UI::build_track_menu ()
1645 {
1646         using namespace Menu_Helpers;
1647         using namespace Gtk;
1648
1649         track_menu = new Menu;
1650         track_menu->set_name ("ArdourContextMenu");
1651         MenuList& items = track_menu->items();
1652
1653         items.push_back (MenuElem (_("Show All"), sigc::mem_fun(*this, &Mixer_UI::show_all_routes)));
1654         items.push_back (MenuElem (_("Hide All"), sigc::mem_fun(*this, &Mixer_UI::hide_all_routes)));
1655         items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
1656         items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
1657         items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus)));
1658         items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
1659         items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &Mixer_UI::show_all_miditracks)));
1660         items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &Mixer_UI::hide_all_miditracks)));
1661
1662 }
1663
1664 void
1665 Mixer_UI::stripable_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Stripable> ws)
1666 {
1667         if (!what_changed.contains (ARDOUR::Properties::hidden) && !what_changed.contains (ARDOUR::Properties::name)) {
1668                 return;
1669         }
1670
1671         boost::shared_ptr<Stripable> s = ws.lock ();
1672
1673         if (!s) {
1674                 return;
1675         }
1676
1677         TreeModel::Children rows = track_model->children();
1678         TreeModel::Children::iterator i;
1679
1680         for (i = rows.begin(); i != rows.end(); ++i) {
1681                 boost::shared_ptr<Stripable> ss = (*i)[stripable_columns.stripable];
1682
1683                 if (s == ss) {
1684
1685                         if (what_changed.contains (ARDOUR::Properties::name)) {
1686                                 (*i)[stripable_columns.text] = s->name();
1687                         }
1688
1689                         if (what_changed.contains (ARDOUR::Properties::hidden)) {
1690                                 (*i)[stripable_columns.visible] = !s->presentation_info().hidden();
1691                                 redisplay_track_list ();
1692                         }
1693
1694                         return;
1695                 }
1696         }
1697
1698         error << _("track display list item for renamed strip not found!") << endmsg;
1699 }
1700
1701 bool
1702 Mixer_UI::group_display_button_press (GdkEventButton* ev)
1703 {
1704         TreeModel::Path path;
1705         TreeViewColumn* column;
1706         int cellx;
1707         int celly;
1708
1709         if (!group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
1710                 if (ev->button == 3) {
1711                         _group_tabs->get_menu(0)->popup (ev->button, ev->time);
1712                 }
1713                 return true;
1714         }
1715
1716         TreeIter iter = group_model->get_iter (path);
1717         if (!iter) {
1718                 if (ev->button == 3) {
1719                         _group_tabs->get_menu(0)->popup (ev->button, ev->time);
1720                 }
1721                 return true;
1722         }
1723
1724         RouteGroup* group = (*iter)[group_columns.group];
1725
1726         if (Keyboard::is_context_menu_event (ev)) {
1727                 _group_tabs->get_menu(group)->popup (1, ev->time);
1728                 return true;
1729         }
1730
1731         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
1732         case 1:
1733                 if (Keyboard::is_edit_event (ev)) {
1734                         if (group) {
1735                                 // edit_route_group (group);
1736 #ifdef __APPLE__
1737                                 group_display.queue_draw();
1738 #endif
1739                                 return true;
1740                         }
1741                 }
1742                 break;
1743
1744         case 0:
1745         {
1746                 bool visible = (*iter)[group_columns.visible];
1747                 (*iter)[group_columns.visible] = !visible;
1748 #ifdef __APPLE__
1749                 group_display.queue_draw();
1750 #endif
1751                 return true;
1752         }
1753
1754         default:
1755                 break;
1756         }
1757
1758         return false;
1759  }
1760
1761 void
1762 Mixer_UI::activate_all_route_groups ()
1763 {
1764         _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), true));
1765 }
1766
1767 void
1768 Mixer_UI::disable_all_route_groups ()
1769 {
1770         _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), false));
1771 }
1772
1773 void
1774 Mixer_UI::route_groups_changed ()
1775 {
1776         ENSURE_GUI_THREAD (*this, &Mixer_UI::route_groups_changed);
1777
1778         _in_group_rebuild_or_clear = true;
1779
1780         /* just rebuild the while thing */
1781
1782         group_model->clear ();
1783
1784 #if 0
1785         /* this is currently not used,
1786          * Mixer_UI::group_display_button_press() has a case for it,
1787          * and a commented edit_route_group() but that's n/a since 2011.
1788          *
1789          * This code is left as reminder that
1790          * row[group_columns.group] = 0 has special meaning.
1791          */
1792         {
1793                 TreeModel::Row row;
1794                 row = *(group_model->append());
1795                 row[group_columns.visible] = true;
1796                 row[group_columns.text] = (_("-all-"));
1797                 row[group_columns.group] = 0;
1798         }
1799 #endif
1800
1801         _session->foreach_route_group (sigc::mem_fun (*this, &Mixer_UI::add_route_group));
1802
1803         _group_tabs->set_dirty ();
1804         _in_group_rebuild_or_clear = false;
1805 }
1806
1807 void
1808 Mixer_UI::new_route_group ()
1809 {
1810         _group_tabs->run_new_group_dialog (0, false);
1811 }
1812
1813 void
1814 Mixer_UI::remove_selected_route_group ()
1815 {
1816         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1817         TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1818
1819         if (rows.empty()) {
1820                 return;
1821         }
1822
1823         TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1824         TreeIter iter;
1825
1826         /* selection mode is single, so rows.begin() is it */
1827
1828         if ((iter = group_model->get_iter (*i))) {
1829
1830                 RouteGroup* rg = (*iter)[group_columns.group];
1831
1832                 if (rg) {
1833                         _session->remove_route_group (*rg);
1834                 }
1835         }
1836 }
1837
1838 void
1839 Mixer_UI::route_group_property_changed (RouteGroup* group, const PropertyChange& change)
1840 {
1841         if (in_group_row_change) {
1842                 return;
1843         }
1844
1845         /* force an update of any mixer strips that are using this group,
1846            otherwise mix group names don't change in mixer strips
1847         */
1848
1849         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1850                 if ((*i)->route_group() == group) {
1851                         (*i)->route_group_changed();
1852                 }
1853         }
1854
1855         TreeModel::iterator i;
1856         TreeModel::Children rows = group_model->children();
1857         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1858
1859         in_group_row_change = true;
1860
1861         for (i = rows.begin(); i != rows.end(); ++i) {
1862                 if ((*i)[group_columns.group] == group) {
1863                         (*i)[group_columns.visible] = !group->is_hidden ();
1864                         (*i)[group_columns.text] = group->name ();
1865                         break;
1866                 }
1867         }
1868
1869         in_group_row_change = false;
1870
1871         if (change.contains (Properties::name)) {
1872                 _group_tabs->set_dirty ();
1873         }
1874
1875         for (list<MixerStrip*>::iterator j = strips.begin(); j != strips.end(); ++j) {
1876                 if ((*j)->route_group() == group) {
1877                         if (group->is_hidden ()) {
1878                                 hide_strip (*j);
1879                         } else {
1880                                 show_strip (*j);
1881                         }
1882                 }
1883         }
1884 }
1885
1886 void
1887 Mixer_UI::show_mixer_list (bool yn)
1888 {
1889         if (yn) {
1890                 list_vpacker.show ();
1891         } else {
1892                 list_vpacker.hide ();
1893         }
1894
1895         _show_mixer_list = yn;
1896 }
1897
1898 void
1899 Mixer_UI::show_monitor_section (bool yn)
1900 {
1901         if (!monitor_section()) {
1902                 return;
1903         }
1904         if (monitor_section()->tearoff().torn_off()) {
1905                 return;
1906         }
1907
1908         if (yn) {
1909                 monitor_section()->tearoff().show();
1910         } else {
1911                 monitor_section()->tearoff().hide();
1912         }
1913 }
1914
1915 void
1916 Mixer_UI::route_group_name_edit (const std::string& path, const std::string& new_text)
1917 {
1918         RouteGroup* group;
1919         TreeIter iter;
1920
1921         if ((iter = group_model->get_iter (path))) {
1922
1923                 if ((group = (*iter)[group_columns.group]) == 0) {
1924                         return;
1925                 }
1926
1927                 if (new_text != group->name()) {
1928                         group->set_name (new_text);
1929                 }
1930         }
1931 }
1932
1933 void
1934 Mixer_UI::route_group_row_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator& iter)
1935 {
1936         RouteGroup* group;
1937
1938         if (in_group_row_change) {
1939                 return;
1940         }
1941
1942         if ((group = (*iter)[group_columns.group]) == 0) {
1943                 return;
1944         }
1945
1946         std::string name = (*iter)[group_columns.text];
1947
1948         if (name != group->name()) {
1949                 group->set_name (name);
1950         }
1951
1952         bool hidden = !(*iter)[group_columns.visible];
1953
1954         if (hidden != group->is_hidden ()) {
1955                 group->set_hidden (hidden, this);
1956         }
1957 }
1958
1959 /** Called when a group model row is deleted, but also when the model is
1960  *  reordered by a user drag-and-drop; the latter is what we are
1961  *  interested in here.
1962  */
1963 void
1964 Mixer_UI::route_group_row_deleted (Gtk::TreeModel::Path const &)
1965 {
1966         if (_in_group_rebuild_or_clear) {
1967                 return;
1968         }
1969
1970         /* Re-write the session's route group list so that the new order is preserved */
1971
1972         list<RouteGroup*> new_list;
1973
1974         Gtk::TreeModel::Children children = group_model->children();
1975         for (Gtk::TreeModel::Children::iterator i = children.begin(); i != children.end(); ++i) {
1976                 RouteGroup* g = (*i)[group_columns.group];
1977                 if (g) {
1978                         new_list.push_back (g);
1979                 }
1980         }
1981
1982         _session->reorder_route_groups (new_list);
1983 }
1984
1985
1986 void
1987 Mixer_UI::add_route_group (RouteGroup* group)
1988 {
1989         ENSURE_GUI_THREAD (*this, &Mixer_UI::add_route_group, group)
1990         bool focus = false;
1991
1992         in_group_row_change = true;
1993
1994         TreeModel::Row row = *(group_model->append());
1995         row[group_columns.visible] = !group->is_hidden ();
1996         row[group_columns.group] = group;
1997         if (!group->name().empty()) {
1998                 row[group_columns.text] = group->name();
1999         } else {
2000                 row[group_columns.text] = _("unnamed");
2001                 focus = true;
2002         }
2003
2004         group->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::route_group_property_changed, this, group, _1), gui_context());
2005
2006         if (focus) {
2007                 TreeViewColumn* col = group_display.get_column (0);
2008                 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (1));
2009                 group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true);
2010         }
2011
2012         _group_tabs->set_dirty ();
2013
2014         in_group_row_change = false;
2015 }
2016
2017 bool
2018 Mixer_UI::strip_scroller_button_release (GdkEventButton* ev)
2019 {
2020         using namespace Menu_Helpers;
2021
2022         if (Keyboard::is_context_menu_event (ev)) {
2023                 ARDOUR_UI::instance()->add_route ();
2024                 return true;
2025         }
2026
2027         return false;
2028 }
2029
2030 void
2031 Mixer_UI::scroller_drag_data_received (const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, const Gtk::SelectionData& data, guint info, guint time)
2032 {
2033         printf ("Mixer_UI::scroller_drag_data_received\n");
2034         if (data.get_target() != "PluginFavoritePtr") {
2035                 context->drag_finish (false, false, time);
2036                 return;
2037         }
2038
2039         const void * d = data.get_data();
2040         const Gtkmm2ext::DnDTreeView<ARDOUR::PluginPresetPtr>* tv = reinterpret_cast<const Gtkmm2ext::DnDTreeView<ARDOUR::PluginPresetPtr>*>(d);
2041
2042         PluginPresetList nfos;
2043         TreeView* source;
2044         tv->get_object_drag_data (nfos, &source);
2045
2046         Route::ProcessorList pl;
2047         bool ok = false;
2048
2049         for (list<PluginPresetPtr>::const_iterator i = nfos.begin(); i != nfos.end(); ++i) {
2050                 PluginPresetPtr ppp = (*i);
2051                 PluginInfoPtr pip = ppp->_pip;
2052                 if (!pip->is_instrument ()) {
2053                         continue;
2054                 }
2055                 ARDOUR_UI::instance()->session_add_midi_track ((RouteGroup*) 0, 1, _("MIDI"), Config->get_strict_io (), pip, ppp->_preset.valid ? &ppp->_preset : 0, PresentationInfo::max_order);
2056                 ok = true;
2057         }
2058
2059         context->drag_finish (ok, false, time);
2060 }
2061
2062 void
2063 Mixer_UI::set_strip_width (Width w, bool save)
2064 {
2065         _strip_width = w;
2066
2067         for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
2068                 (*i)->set_width_enum (w, save ? (*i)->width_owner() : this);
2069         }
2070 }
2071
2072
2073 struct PluginStateSorter {
2074 public:
2075         bool operator() (PluginInfoPtr a, PluginInfoPtr b) const {
2076                 std::list<std::string>::const_iterator aiter = std::find(_user.begin(), _user.end(), (*a).unique_id);
2077                 std::list<std::string>::const_iterator biter = std::find(_user.begin(), _user.end(), (*b).unique_id);
2078                 if (aiter != _user.end() && biter != _user.end()) {
2079                         return std::distance (_user.begin(), aiter)  < std::distance (_user.begin(), biter);
2080                 }
2081                 if (aiter != _user.end()) {
2082                         return true;
2083                 }
2084                 if (biter != _user.end()) {
2085                         return false;
2086                 }
2087                 return ARDOUR::cmp_nocase((*a).name, (*b).name) == -1;
2088         }
2089
2090         PluginStateSorter(std::list<std::string> user) : _user (user)  {}
2091 private:
2092         std::list<std::string> _user;
2093 };
2094
2095 int
2096 Mixer_UI::set_state (const XMLNode& node, int version)
2097 {
2098         LocaleGuard lg;
2099         bool yn;
2100
2101         Tabbable::set_state (node, version);
2102
2103         if (node.get_property ("narrow-strips", yn)) {
2104                 if (yn) {
2105                         set_strip_width (Narrow);
2106                 } else {
2107                         set_strip_width (Wide);
2108                 }
2109         }
2110
2111         node.get_property ("show-mixer", _visible);
2112
2113         if (node.get_property ("maximised", yn)) {
2114                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalMixer"));
2115                 assert (act);
2116                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2117                 bool fs = tact && tact->get_active();
2118                 if (yn ^ fs) {
2119                         ActionManager::do_action ("Common", "ToggleMaximalMixer");
2120                 }
2121         }
2122
2123         if (node.get_property ("show-mixer-list", yn)) {
2124                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMixerList"));
2125                 assert (act);
2126                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2127
2128                 /* do it twice to force the change */
2129                 tact->set_active (!yn);
2130                 tact->set_active (yn);
2131         }
2132
2133
2134         XMLNode* plugin_order;
2135         if ((plugin_order = find_named_node (node, "PluginOrder")) != 0) {
2136                 store_current_favorite_order ();
2137                 std::list<string> order;
2138                 const XMLNodeList& kids = plugin_order->children("PluginInfo");
2139                 XMLNodeConstIterator i;
2140                 for (i = kids.begin(); i != kids.end(); ++i) {
2141                         std::string unique_id;
2142                         if ((*i)->get_property ("unique-id", unique_id)) {
2143                                 order.push_back (unique_id);
2144                                 if ((*i)->get_property ("expanded", yn)) {
2145                                         favorite_ui_state[unique_id] = yn;
2146                                 }
2147                         }
2148                 }
2149                 PluginStateSorter cmp (order);
2150                 favorite_order.sort (cmp);
2151                 sync_treeview_from_favorite_order ();
2152         }
2153         return 0;
2154 }
2155
2156 XMLNode&
2157 Mixer_UI::get_state ()
2158 {
2159         XMLNode* node = new XMLNode (X_("Mixer"));
2160         LocaleGuard lg;
2161
2162         node->add_child_nocopy (Tabbable::get_state());
2163
2164         node->set_property (X_("mixer-rhs-pane1-pos"), rhs_pane1.get_divider());
2165         node->set_property (X_("mixer-rhs_pane2-pos"), rhs_pane2.get_divider());
2166         node->set_property (X_("mixer-list-hpane-pos"), list_hpane.get_divider());
2167         node->set_property (X_("mixer-inner-pane-pos"),  inner_pane.get_divider());
2168
2169         node->set_property ("narrow-strips", (_strip_width == Narrow));
2170         node->set_property ("show-mixer", _visible);
2171         node->set_property ("show-mixer-list", _show_mixer_list);
2172         node->set_property ("maximised", _maximised);
2173
2174         store_current_favorite_order ();
2175         XMLNode* plugin_order = new XMLNode ("PluginOrder");
2176         uint32_t cnt = 0;
2177         for (PluginInfoList::const_iterator i = favorite_order.begin(); i != favorite_order.end(); ++i, ++cnt) {
2178                 XMLNode* p = new XMLNode ("PluginInfo");
2179                 p->set_property ("sort", cnt);
2180                 p->set_property ("unique-id", (*i)->unique_id);
2181                 if (favorite_ui_state.find ((*i)->unique_id) != favorite_ui_state.end ()) {
2182                         p->set_property ("expanded", favorite_ui_state[(*i)->unique_id]);
2183                 }
2184                 plugin_order->add_child_nocopy (*p);
2185         }
2186         node->add_child_nocopy (*plugin_order);
2187
2188         return *node;
2189 }
2190
2191 void
2192 Mixer_UI::scroll_left ()
2193 {
2194         if (!scroller.get_hscrollbar()) return;
2195         Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
2196         int sc_w = scroller.get_width();
2197         int sp_w = strip_packer.get_width();
2198         if (sp_w <= sc_w) {
2199                 return;
2200         }
2201         int lp = adj->get_value();
2202         int lm = 0;
2203         using namespace Gtk::Box_Helpers;
2204         const BoxList& strips = strip_packer.children();
2205         for (BoxList::const_iterator i = strips.begin(); i != strips.end(); ++i) {
2206                 lm += i->get_widget()->get_width ();
2207                 if (lm >= lp) {
2208                         lm -= i->get_widget()->get_width ();
2209                         break;
2210                 }
2211         }
2212         scroller.get_hscrollbar()->set_value (max (adj->get_lower(), min (adj->get_upper(), lm - 1.0)));
2213 }
2214
2215 void
2216 Mixer_UI::scroll_right ()
2217 {
2218         if (!scroller.get_hscrollbar()) return;
2219         Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
2220         int sc_w = scroller.get_width();
2221         int sp_w = strip_packer.get_width();
2222         if (sp_w <= sc_w) {
2223                 return;
2224         }
2225         int lp = adj->get_value();
2226         int lm = 0;
2227         using namespace Gtk::Box_Helpers;
2228         const BoxList& strips = strip_packer.children();
2229         for (BoxList::const_iterator i = strips.begin(); i != strips.end(); ++i) {
2230                 lm += i->get_widget()->get_width ();
2231                 if (lm > lp + 1) {
2232                         break;
2233                 }
2234         }
2235         scroller.get_hscrollbar()->set_value (max (adj->get_lower(), min (adj->get_upper(), lm - 1.0)));
2236 }
2237
2238 bool
2239 Mixer_UI::on_scroll_event (GdkEventScroll* ev)
2240 {
2241         switch (ev->direction) {
2242         case GDK_SCROLL_LEFT:
2243                 scroll_left ();
2244                 return true;
2245         case GDK_SCROLL_UP:
2246                 if (ev->state & Keyboard::TertiaryModifier) {
2247                         scroll_left ();
2248                         return true;
2249                 }
2250                 return false;
2251
2252         case GDK_SCROLL_RIGHT:
2253                 scroll_right ();
2254                 return true;
2255
2256         case GDK_SCROLL_DOWN:
2257                 if (ev->state & Keyboard::TertiaryModifier) {
2258                         scroll_right ();
2259                         return true;
2260                 }
2261                 return false;
2262         }
2263
2264         return false;
2265 }
2266
2267
2268 void
2269 Mixer_UI::parameter_changed (string const & p)
2270 {
2271         if (p == "show-group-tabs") {
2272                 bool const s = _session->config.get_show_group_tabs ();
2273                 if (s) {
2274                         _group_tabs->show ();
2275                 } else {
2276                         _group_tabs->hide ();
2277                 }
2278         } else if (p == "default-narrow_ms") {
2279                 bool const s = UIConfiguration::instance().get_default_narrow_ms ();
2280                 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
2281                         (*i)->set_width_enum (s ? Narrow : Wide, this);
2282                 }
2283         } else if (p == "use-monitor-bus") {
2284                 if (_session && !_session->monitor_out()) {
2285                         monitor_section_detached ();
2286                 }
2287         }
2288 }
2289
2290 void
2291 Mixer_UI::set_route_group_activation (RouteGroup* g, bool a)
2292 {
2293         g->set_active (a, this);
2294 }
2295
2296 PluginSelector*
2297 Mixer_UI::plugin_selector()
2298 {
2299 #ifdef DEFER_PLUGIN_SELECTOR_LOAD
2300         if (!_plugin_selector)
2301                 _plugin_selector = new PluginSelector (PluginManager::instance());
2302 #endif
2303
2304         return _plugin_selector;
2305 }
2306
2307 void
2308 Mixer_UI::setup_track_display ()
2309 {
2310         track_model = ListStore::create (stripable_columns);
2311         track_display.set_model (track_model);
2312         track_display.append_column (_("Show"), stripable_columns.visible);
2313         track_display.append_column (_("Strips"), stripable_columns.text);
2314         track_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
2315         track_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
2316         track_display.get_column (0)->set_expand(false);
2317         track_display.get_column (1)->set_expand(true);
2318         track_display.get_column (1)->set_sizing (Gtk::TREE_VIEW_COLUMN_FIXED);
2319         track_display.set_name (X_("EditGroupList"));
2320         track_display.get_selection()->set_mode (Gtk::SELECTION_NONE);
2321         track_display.set_reorderable (true);
2322         track_display.set_headers_visible (true);
2323         track_display.set_can_focus(false);
2324
2325         track_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_delete));
2326         track_model->signal_rows_reordered().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_reorder));
2327
2328         CellRendererToggle* track_list_visible_cell = dynamic_cast<CellRendererToggle*>(track_display.get_column_cell_renderer (0));
2329         track_list_visible_cell->property_activatable() = true;
2330         track_list_visible_cell->property_radio() = false;
2331         track_list_visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &Mixer_UI::track_visibility_changed));
2332
2333         track_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::track_display_button_press), false);
2334
2335         track_display_scroller.add (track_display);
2336         track_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2337
2338         VBox* v = manage (new VBox);
2339         v->show ();
2340         v->pack_start (track_display_scroller, true, true);
2341
2342         Button* b = manage (new Button);
2343         b->show ();
2344         Widget* w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
2345         w->show ();
2346         b->add (*w);
2347
2348         b->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus));
2349
2350         v->pack_start (*b, false, false);
2351
2352         track_display_frame.set_name("BaseFrame");
2353         track_display_frame.set_shadow_type (Gtk::SHADOW_IN);
2354         track_display_frame.add (*v);
2355
2356         track_display_scroller.show();
2357         track_display_frame.show();
2358         track_display.show();
2359 }
2360
2361 void
2362 Mixer_UI::new_track_or_bus ()
2363 {
2364         ARDOUR_UI::instance()->add_route ();
2365 }
2366
2367 void
2368 Mixer_UI::update_title ()
2369 {
2370         if (!own_window()) {
2371                 return;
2372         }
2373
2374         if (_session) {
2375                 string n;
2376
2377                 if (_session->snap_name() != _session->name()) {
2378                         n = _session->snap_name ();
2379                 } else {
2380                         n = _session->name ();
2381                 }
2382
2383                 if (_session->dirty ()) {
2384                         n = "*" + n;
2385                 }
2386
2387                 WindowTitle title (n);
2388                 title += S_("Window|Mixer");
2389                 title += Glib::get_application_name ();
2390                 own_window()->set_title (title.get_string());
2391
2392         } else {
2393
2394                 WindowTitle title (S_("Window|Mixer"));
2395                 title += Glib::get_application_name ();
2396                 own_window()->set_title (title.get_string());
2397         }
2398 }
2399
2400 MixerStrip*
2401 Mixer_UI::strip_by_x (int x)
2402 {
2403         for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
2404                 int x1, x2, y;
2405
2406                 (*i)->translate_coordinates (_content, 0, 0, x1, y);
2407                 x2 = x1 + (*i)->get_width();
2408
2409                 if (x >= x1 && x <= x2) {
2410                         return (*i);
2411                 }
2412         }
2413
2414         return 0;
2415 }
2416
2417 void
2418 Mixer_UI::set_axis_targets_for_operation ()
2419 {
2420         _axis_targets.clear ();
2421
2422         if (!_selection.empty()) {
2423                 _axis_targets = _selection.axes;
2424                 return;
2425         }
2426
2427 //  removed "implicit" selections of strips, after discussion on IRC
2428
2429 }
2430
2431 void
2432 Mixer_UI::monitor_section_going_away ()
2433 {
2434         if (_monitor_section) {
2435                 monitor_section_detached ();
2436                 out_packer.remove (_monitor_section->tearoff());
2437                 _monitor_section->set_session (0);
2438                 delete _monitor_section;
2439                 _monitor_section = 0;
2440         }
2441 }
2442
2443 void
2444 Mixer_UI::toggle_midi_input_active (bool flip_others)
2445 {
2446         boost::shared_ptr<RouteList> rl (new RouteList);
2447         bool onoff = false;
2448
2449         set_axis_targets_for_operation ();
2450
2451         for (AxisViewSelection::iterator r = _axis_targets.begin(); r != _axis_targets.end(); ++r) {
2452                 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> ((*r)->stripable());
2453
2454                 if (mt) {
2455                         rl->push_back (mt);
2456                         onoff = !mt->input_active();
2457                 }
2458         }
2459
2460         _session->set_exclusive_input_active (rl, onoff, flip_others);
2461 }
2462
2463 void
2464 Mixer_UI::maximise_mixer_space ()
2465 {
2466         if (!own_window()) {
2467                 return;
2468         }
2469
2470         if (_maximised) {
2471                 return;
2472         }
2473
2474         _window->fullscreen ();
2475         _maximised = true;
2476 }
2477
2478 void
2479 Mixer_UI::restore_mixer_space ()
2480 {
2481         if (!own_window()) {
2482                 return;
2483         }
2484
2485         if (!_maximised) {
2486                 return;
2487         }
2488
2489         own_window()->unfullscreen();
2490         _maximised = false;
2491 }
2492
2493 void
2494 Mixer_UI::monitor_section_attached ()
2495 {
2496         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
2497         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2498         act->set_sensitive (true);
2499         tact->set_active ();
2500 }
2501
2502 void
2503 Mixer_UI::monitor_section_detached ()
2504 {
2505         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
2506         act->set_sensitive (false);
2507 }
2508
2509 void
2510 Mixer_UI::store_current_favorite_order ()
2511 {
2512         typedef Gtk::TreeModel::Children type_children;
2513         type_children children = favorite_plugins_model->children();
2514         favorite_order.clear();
2515         for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter)
2516         {
2517                 Gtk::TreeModel::Row row = *iter;
2518                 ARDOUR::PluginPresetPtr ppp = row[favorite_plugins_columns.plugin];
2519                 favorite_order.push_back (ppp->_pip);
2520                 std::string name = row[favorite_plugins_columns.name];
2521                 favorite_ui_state[(*ppp->_pip).unique_id] = favorite_plugins_display.row_expanded (favorite_plugins_model->get_path(iter));
2522         }
2523 }
2524
2525 void
2526 Mixer_UI::save_favorite_ui_state (const TreeModel::iterator& iter, const TreeModel::Path& path)
2527 {
2528         Gtk::TreeModel::Row row = *iter;
2529         ARDOUR::PluginPresetPtr ppp = row[favorite_plugins_columns.plugin];
2530         assert (ppp);
2531         favorite_ui_state[(*ppp->_pip).unique_id] = favorite_plugins_display.row_expanded (favorite_plugins_model->get_path(iter));
2532 }
2533
2534 void
2535 Mixer_UI::refiller (PluginInfoList& result, const PluginInfoList& plugs)
2536 {
2537         PluginManager& manager (PluginManager::instance());
2538         for (PluginInfoList::const_iterator i = plugs.begin(); i != plugs.end(); ++i) {
2539                 if (manager.get_status (*i) != PluginManager::Favorite) {
2540                         continue;
2541                 }
2542                 result.push_back (*i);
2543         }
2544 }
2545
2546 struct PluginCustomSorter {
2547 public:
2548         bool operator() (PluginInfoPtr a, PluginInfoPtr b) const {
2549                 PluginInfoList::const_iterator aiter = _user.begin();
2550                 PluginInfoList::const_iterator biter = _user.begin();
2551                 while (aiter != _user.end()) { if ((*aiter)->unique_id == a->unique_id) { break; } ++aiter; }
2552                 while (biter != _user.end()) { if ((*biter)->unique_id == b->unique_id) { break; } ++biter; }
2553
2554                 if (aiter != _user.end() && biter != _user.end()) {
2555                         return std::distance (_user.begin(), aiter) < std::distance (_user.begin(), biter);
2556                 }
2557                 if (aiter != _user.end()) {
2558                         return true;
2559                 }
2560                 if (biter != _user.end()) {
2561                         return false;
2562                 }
2563                 return ARDOUR::cmp_nocase((*a).name, (*b).name) == -1;
2564         }
2565         PluginCustomSorter(PluginInfoList user) : _user (user)  {}
2566 private:
2567         PluginInfoList _user;
2568 };
2569
2570 void
2571 Mixer_UI::refill_favorite_plugins ()
2572 {
2573         PluginInfoList plugs;
2574         PluginManager& mgr (PluginManager::instance());
2575
2576 #ifdef LV2_SUPPORT
2577         refiller (plugs, mgr.lv2_plugin_info ());
2578 #endif
2579 #ifdef WINDOWS_VST_SUPPORT
2580         refiller (plugs, mgr.windows_vst_plugin_info ());
2581 #endif
2582 #ifdef LXVST_SUPPORT
2583         refiller (plugs, mgr.lxvst_plugin_info ());
2584 #endif
2585 #ifdef MACVST_SUPPORT
2586         refiller (plugs, mgr.mac_vst_plugin_info ());
2587 #endif
2588 #ifdef AUDIOUNIT_SUPPORT
2589         refiller (plugs, mgr.au_plugin_info ());
2590 #endif
2591         refiller (plugs, mgr.ladspa_plugin_info ());
2592         refiller (plugs, mgr.lua_plugin_info ());
2593
2594         store_current_favorite_order ();
2595
2596         PluginCustomSorter cmp (favorite_order);
2597         plugs.sort (cmp);
2598
2599         favorite_order = plugs;
2600
2601         sync_treeview_from_favorite_order ();
2602 }
2603
2604 void
2605 Mixer_UI::sync_treeview_favorite_ui_state (const TreeModel::Path& path, const TreeModel::iterator&)
2606 {
2607         TreeIter iter;
2608         if (!(iter = favorite_plugins_model->get_iter (path))) {
2609                 return;
2610         }
2611         ARDOUR::PluginPresetPtr ppp = (*iter)[favorite_plugins_columns.plugin];
2612         if (!ppp) {
2613                 return;
2614         }
2615         PluginInfoPtr pip = ppp->_pip;
2616         if (favorite_ui_state.find (pip->unique_id) != favorite_ui_state.end ()) {
2617                 if (favorite_ui_state[pip->unique_id]) {
2618                         favorite_plugins_display.expand_row (path, true);
2619                 }
2620         }
2621 }
2622
2623 void
2624 Mixer_UI::sync_treeview_from_favorite_order ()
2625 {
2626         favorite_plugins_model->clear ();
2627         for (PluginInfoList::const_iterator i = favorite_order.begin(); i != favorite_order.end(); ++i) {
2628                 PluginInfoPtr pip = (*i);
2629
2630                 TreeModel::Row newrow = *(favorite_plugins_model->append());
2631                 newrow[favorite_plugins_columns.name] = (*i)->name;
2632                 newrow[favorite_plugins_columns.plugin] = PluginPresetPtr (new PluginPreset(pip));
2633                 if (!_session) {
2634                         continue;
2635                 }
2636
2637                 vector<ARDOUR::Plugin::PresetRecord> presets = (*i)->get_presets (true);
2638                 for (vector<ARDOUR::Plugin::PresetRecord>::const_iterator j = presets.begin(); j != presets.end(); ++j) {
2639                         Gtk::TreeModel::Row child_row = *(favorite_plugins_model->append (newrow.children()));
2640                         child_row[favorite_plugins_columns.name] = (*j).label;
2641                         child_row[favorite_plugins_columns.plugin] = PluginPresetPtr (new PluginPreset(pip, &(*j)));
2642                 }
2643                 if (favorite_ui_state.find (pip->unique_id) != favorite_ui_state.end ()) {
2644                         if (favorite_ui_state[pip->unique_id]) {
2645                                 favorite_plugins_display.expand_row (favorite_plugins_model->get_path(newrow), true);
2646                         }
2647                 }
2648         }
2649 }
2650
2651 void
2652 Mixer_UI::popup_note_context_menu (GdkEventButton *ev)
2653 {
2654         using namespace Gtk::Menu_Helpers;
2655
2656         Gtk::Menu* m = manage (new Menu);
2657         MenuList& items = m->items ();
2658
2659         if (_selection.axes.empty()) {
2660                 items.push_back (MenuElem (_("No Track/Bus is selected.")));
2661         } else {
2662                 items.push_back (MenuElem (_("Add at the top"),
2663                                         sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddTop)));
2664                 items.push_back (MenuElem (_("Add Pre-Fader"),
2665                                         sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddPreFader)));
2666                 items.push_back (MenuElem (_("Add Post-Fader"),
2667                                         sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddPostFader)));
2668                 items.push_back (MenuElem (_("Add at the end"),
2669                                         sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddBottom)));
2670         }
2671
2672         items.push_back (SeparatorElem());
2673
2674         items.push_back (MenuElem (_("Remove from favorites"), sigc::mem_fun (*this, &Mixer_UI::remove_selected_from_favorites)));
2675
2676         ARDOUR::PluginPresetPtr ppp = selected_plugin();
2677         if (ppp && ppp->_preset.valid && ppp->_preset.user) {
2678                 // we cannot currently delete AU presets
2679                 if (!ppp->_pip || ppp->_pip->type != AudioUnit) {
2680                         items.push_back (MenuElem (_("Delete Preset"), sigc::mem_fun (*this, &Mixer_UI::delete_selected_preset)));
2681                 }
2682         }
2683
2684         m->popup (ev->button, ev->time);
2685 }
2686
2687 bool
2688 Mixer_UI::plugin_row_button_press (GdkEventButton *ev)
2689 {
2690         if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 3) ) {
2691                 TreeModel::Path path;
2692                 TreeViewColumn* column;
2693                 int cellx, celly;
2694                 if (favorite_plugins_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
2695                         Glib::RefPtr<Gtk::TreeView::Selection> selection = favorite_plugins_display.get_selection();
2696                         if (selection) {
2697                                 selection->unselect_all();
2698                                 selection->select(path);
2699                         }
2700                 }
2701                 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2702                 if (ppp) {
2703                         popup_note_context_menu (ev);
2704                 }
2705         }
2706         return false;
2707 }
2708
2709
2710 PluginPresetPtr
2711 Mixer_UI::selected_plugin ()
2712 {
2713         Glib::RefPtr<Gtk::TreeView::Selection> selection = favorite_plugins_display.get_selection();
2714         if (!selection) {
2715                 return PluginPresetPtr();
2716         }
2717         Gtk::TreeModel::iterator iter = selection->get_selected();
2718         if (!iter) {
2719                 return PluginPresetPtr();
2720         }
2721         return (*iter)[favorite_plugins_columns.plugin];
2722 }
2723
2724 void
2725 Mixer_UI::add_selected_processor (ProcessorPosition pos)
2726 {
2727         ARDOUR::PluginPresetPtr ppp = selected_plugin();
2728         if (ppp) {
2729                 add_favorite_processor (ppp, pos);
2730         }
2731 }
2732
2733 void
2734 Mixer_UI::delete_selected_preset ()
2735 {
2736         if (!_session) {
2737                 return;
2738         }
2739         ARDOUR::PluginPresetPtr ppp = selected_plugin();
2740         if (!ppp || !ppp->_preset.valid || !ppp->_preset.user) {
2741                 return;
2742         }
2743         PluginPtr plugin = ppp->_pip->load (*_session);
2744         plugin->get_presets();
2745         plugin->remove_preset (ppp->_preset.label);
2746 }
2747
2748 void
2749 Mixer_UI::remove_selected_from_favorites ()
2750 {
2751         ARDOUR::PluginPresetPtr ppp = selected_plugin();
2752         if (!ppp) {
2753                 return;
2754         }
2755         PluginManager::PluginStatusType status = PluginManager::Normal;
2756         PluginManager& manager (PluginManager::instance());
2757
2758         manager.set_status (ppp->_pip->type, ppp->_pip->unique_id, status);
2759         manager.save_statuses ();
2760 }
2761
2762 void
2763 Mixer_UI::plugin_row_activated (const TreeModel::Path& path, TreeViewColumn* column)
2764 {
2765         TreeIter iter;
2766         if (!(iter = favorite_plugins_model->get_iter (path))) {
2767                 return;
2768         }
2769         ARDOUR::PluginPresetPtr ppp = (*iter)[favorite_plugins_columns.plugin];
2770         add_favorite_processor (ppp, AddPreFader); // TODO: preference?!
2771 }
2772
2773 void
2774 Mixer_UI::add_favorite_processor (ARDOUR::PluginPresetPtr ppp, ProcessorPosition pos)
2775 {
2776         if (!_session || _selection.axes.empty()) {
2777                 return;
2778         }
2779
2780         PluginInfoPtr pip = ppp->_pip;
2781         for (AxisViewSelection::iterator i = _selection.axes.begin(); i != _selection.axes.end(); ++i) {
2782                 boost::shared_ptr<ARDOUR::Route> rt = boost::dynamic_pointer_cast<ARDOUR::Route> ((*i)->stripable());
2783
2784                 if (!rt) {
2785                         continue;
2786                 }
2787
2788                 PluginPtr p = pip->load (*_session);
2789
2790                 if (!p) {
2791                         continue;
2792                 }
2793
2794                 if (ppp->_preset.valid) {
2795                         p->load_preset (ppp->_preset);
2796                 }
2797
2798                 Route::ProcessorStreams err;
2799                 boost::shared_ptr<Processor> processor (new PluginInsert (*_session, p));
2800
2801                 switch (pos) {
2802                         case AddTop:
2803                                 rt->add_processor_by_index (processor, 0, &err, Config->get_new_plugins_active ());
2804                                 break;
2805                         case AddPreFader:
2806                                 rt->add_processor (processor, PreFader, &err, Config->get_new_plugins_active ());
2807                                 break;
2808                         case AddPostFader:
2809                                 {
2810                                         int idx = 0;
2811                                         int pos = 0;
2812                                         for (;;++idx) {
2813                                                 boost::shared_ptr<Processor> np = rt->nth_processor (idx);
2814                                                 if (!np) {
2815                                                         break;
2816                                                 }
2817                                                 if (!np->display_to_user()) {
2818                                                         continue;
2819                                                 }
2820                                                 if (boost::dynamic_pointer_cast<Amp> (np) && // Fader, not Trim
2821                                                                 boost::dynamic_pointer_cast<Amp> (np)->gain_control()->parameter().type() == GainAutomation) {
2822                                                         break;
2823                                                 }
2824                                                 ++pos;
2825                                         }
2826                                         rt->add_processor_by_index (processor, ++pos, &err, Config->get_new_plugins_active ());
2827                                 }
2828                                 break;
2829                         case AddBottom:
2830                                 rt->add_processor_by_index (processor, -1, &err, Config->get_new_plugins_active ());
2831                                 break;
2832                 }
2833         }
2834 }
2835
2836 bool
2837 PluginTreeStore::row_drop_possible_vfunc(const Gtk::TreeModel::Path& dest, const Gtk::SelectionData& data) const
2838 {
2839         if (data.get_target() != "GTK_TREE_MODEL_ROW") {
2840                 return false;
2841         }
2842
2843         // only allow to re-order top-level items
2844         TreePath src;
2845         if (TreePath::get_from_selection_data (data, src)) {
2846                 if (src.up() && src.up()) {
2847                         return false;
2848                 }
2849         }
2850
2851         // don't allow to drop as child-rows.
2852         Gtk::TreeModel::Path _dest = dest; // un const
2853         const bool is_child = _dest.up (); // explicit bool for clang
2854         if (!is_child || _dest.empty ()) {
2855                 return true;
2856         }
2857         return false;
2858 }
2859
2860 void
2861 Mixer_UI::plugin_drop (const Glib::RefPtr<Gdk::DragContext>&, const Gtk::SelectionData& data)
2862 {
2863         if (data.get_target() != "PluginPresetPtr") {
2864                 return;
2865         }
2866         if (data.get_length() != sizeof (PluginPresetPtr)) {
2867                 return;
2868         }
2869         const void *d = data.get_data();
2870         const PluginPresetPtr ppp = *(static_cast<const PluginPresetPtr*> (d));
2871
2872         PluginManager::PluginStatusType status = PluginManager::Favorite;
2873         PluginManager& manager (PluginManager::instance());
2874
2875         manager.set_status (ppp->_pip->type, ppp->_pip->unique_id, status);
2876         manager.save_statuses ();
2877 }
2878
2879 void
2880 Mixer_UI::do_vca_assign (boost::shared_ptr<VCA> vca)
2881 {
2882         /* call protected MixerActor:: method */
2883         vca_assign (vca);
2884 }
2885
2886 void
2887 Mixer_UI::do_vca_unassign (boost::shared_ptr<VCA> vca)
2888 {
2889         /* call protected MixerActor:: method */
2890         vca_unassign (vca);
2891 }
2892
2893 void
2894 Mixer_UI::show_spill (boost::shared_ptr<Stripable> s)
2895 {
2896         boost::shared_ptr<Stripable> ss = spilled_strip.lock();
2897         if (ss != s) {
2898                 spilled_strip = s;
2899                 show_spill_change (s); /* EMIT SIGNAL */
2900                 if (s) {
2901                         _group_tabs->hide ();
2902                 } else {
2903                         _group_tabs->show ();
2904                 }
2905                 redisplay_track_list ();
2906         }
2907 }
2908
2909 bool
2910 Mixer_UI::showing_spill_for (boost::shared_ptr<Stripable> s) const
2911 {
2912         return s == spilled_strip.lock();
2913 }
2914
2915 void
2916 Mixer_UI::show_editor_window () const
2917 {
2918         PublicEditor::instance().make_visible ();
2919 }
2920
2921 void
2922 Mixer_UI::register_actions ()
2923 {
2924         Glib::RefPtr<ActionGroup> group = myactions.create_action_group (X_("Mixer"));
2925
2926         myactions.register_action (group, "show-editor", _("Show Editor"), sigc::mem_fun (*this, &Mixer_UI::show_editor_window));
2927
2928         myactions.register_action (group, "solo", _("Toggle Solo on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::solo_action));
2929         myactions.register_action (group, "mute", _("Toggle Mute on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::mute_action));
2930         myactions.register_action (group, "recenable", _("Toggle Rec-enable on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::rec_enable_action));
2931         myactions.register_action (group, "increment-gain", _("Decrease Gain on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::step_gain_up_action));
2932         myactions.register_action (group, "decrement-gain", _("Increase Gain on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::step_gain_down_action));
2933         myactions.register_action (group, "unity-gain", _("Set Gain to 0dB on Mixer-Selected Tracks/Busses"), sigc::mem_fun (*this, &Mixer_UI::unity_gain_action));
2934
2935
2936         myactions.register_action (group, "copy-processors", _("Copy Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::copy_processors));
2937         myactions.register_action (group, "cut-processors", _("Cut Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::cut_processors));
2938         myactions.register_action (group, "paste-processors", _("Paste Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::paste_processors));
2939         myactions.register_action (group, "delete-processors", _("Delete Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::delete_processors));
2940         myactions.register_action (group, "select-all-processors", _("Select All (visible) Processors"), sigc::mem_fun (*this, &Mixer_UI::select_all_processors));
2941         myactions.register_action (group, "toggle-processors", _("Toggle Selected Processors"), sigc::mem_fun (*this, &Mixer_UI::toggle_processors));
2942         myactions.register_action (group, "ab-plugins", _("Toggle Selected Plugins"), sigc::mem_fun (*this, &Mixer_UI::ab_plugins));
2943         myactions.register_action (group, "select-none", _("Deselect all strips and processors"), sigc::mem_fun (*this, &Mixer_UI::select_none));
2944
2945         myactions.register_action (group, "scroll-left", _("Scroll Mixer Window to the left"), sigc::mem_fun (*this, &Mixer_UI::scroll_left));
2946         myactions.register_action (group, "scroll-right", _("Scroll Mixer Window to the right"), sigc::mem_fun (*this, &Mixer_UI::scroll_right));
2947
2948         myactions.register_action (group, "toggle-midi-input-active", _("Toggle MIDI Input Active for Mixer-Selected Tracks/Busses"),
2949                                    sigc::bind (sigc::mem_fun (*this, &Mixer_UI::toggle_midi_input_active), false));
2950 }
2951
2952 void
2953 Mixer_UI::load_bindings ()
2954 {
2955         bindings = Bindings::get_bindings (X_("Mixer"), myactions);
2956 }
2957
2958 template<class T> void
2959 Mixer_UI::control_action (boost::shared_ptr<T> (Stripable::*get_control)() const)
2960 {
2961         boost::shared_ptr<ControlList> cl (new ControlList);
2962         boost::shared_ptr<AutomationControl> ac;
2963         bool val = false;
2964         bool have_val = false;
2965
2966         set_axis_targets_for_operation ();
2967
2968         BOOST_FOREACH(AxisView* r, _axis_targets) {
2969                 boost::shared_ptr<Stripable> s = r->stripable();
2970                 if (s) {
2971                         ac = (s.get()->*get_control)();
2972                         if (ac) {
2973                                 cl->push_back (ac);
2974                                 if (!have_val) {
2975                                         val = !ac->get_value();
2976                                         have_val = true;
2977                                 }
2978                         }
2979                 }
2980         }
2981
2982         _session->set_controls (cl,  val, Controllable::UseGroup);
2983 }
2984
2985 void
2986 Mixer_UI::solo_action ()
2987 {
2988         control_action (&Stripable::solo_control);
2989 }
2990
2991 void
2992 Mixer_UI::mute_action ()
2993 {
2994         control_action (&Stripable::mute_control);
2995 }
2996
2997 void
2998 Mixer_UI::rec_enable_action ()
2999 {
3000         control_action (&Stripable::rec_enable_control);
3001 }
3002
3003 void
3004 Mixer_UI::step_gain_up_action ()
3005 {
3006         set_axis_targets_for_operation ();
3007
3008         BOOST_FOREACH(AxisView* r, _axis_targets) {
3009                 MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
3010                 if (ms) {
3011                         ms->step_gain_up ();
3012                 }
3013         }
3014 }
3015
3016 void
3017 Mixer_UI::step_gain_down_action ()
3018 {
3019         set_axis_targets_for_operation ();
3020
3021         BOOST_FOREACH(AxisView* r, _axis_targets) {
3022                 MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
3023                 if (ms) {
3024                         ms->step_gain_down ();
3025                 }
3026         }
3027 }
3028
3029 void
3030 Mixer_UI::unity_gain_action ()
3031 {
3032         set_axis_targets_for_operation ();
3033
3034         BOOST_FOREACH(AxisView* r, _axis_targets) {
3035                 boost::shared_ptr<Stripable> s = r->stripable();
3036                 if (s) {
3037                         boost::shared_ptr<AutomationControl> ac = s->gain_control();
3038                         if (ac) {
3039                                 ac->set_value (1.0, Controllable::UseGroup);
3040                         }
3041                 }
3042         }
3043 }
3044
3045 void
3046 Mixer_UI::copy_processors ()
3047 {
3048         set_axis_targets_for_operation ();
3049
3050         BOOST_FOREACH(AxisView* r, _axis_targets) {
3051                 MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
3052                 if (ms) {
3053                         ms->copy_processors ();
3054                 }
3055         }
3056 }
3057 void
3058 Mixer_UI::cut_processors ()
3059 {
3060         set_axis_targets_for_operation ();
3061
3062         BOOST_FOREACH(AxisView* r, _axis_targets) {
3063                 MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
3064                 if (ms) {
3065                         ms->cut_processors ();
3066                 }
3067         }
3068 }
3069 void
3070 Mixer_UI::paste_processors ()
3071 {
3072         set_axis_targets_for_operation ();
3073
3074         BOOST_FOREACH(AxisView* r, _axis_targets) {
3075                 MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
3076                 if (ms) {
3077                         ms->paste_processors ();
3078                 }
3079         }
3080 }
3081 void
3082 Mixer_UI::select_all_processors ()
3083 {
3084         set_axis_targets_for_operation ();
3085
3086         BOOST_FOREACH(AxisView* r, _axis_targets) {
3087                 MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
3088                 if (ms) {
3089                         ms->select_all_processors ();
3090                 }
3091         }
3092 }
3093 void
3094 Mixer_UI::toggle_processors ()
3095 {
3096         set_axis_targets_for_operation ();
3097
3098         BOOST_FOREACH(AxisView* r, _axis_targets) {
3099                 MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
3100                 if (ms) {
3101                         ms->toggle_processors ();
3102                 }
3103         }
3104 }
3105 void
3106 Mixer_UI::ab_plugins ()
3107 {
3108         set_axis_targets_for_operation ();
3109
3110         BOOST_FOREACH(AxisView* r, _axis_targets) {
3111                 MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
3112                 if (ms) {
3113                         ms->ab_plugins ();
3114                 }
3115         }
3116 }
3117
3118 void
3119 Mixer_UI::vca_assign (boost::shared_ptr<VCA> vca)
3120 {
3121         set_axis_targets_for_operation ();
3122         BOOST_FOREACH(AxisView* r, _axis_targets) {
3123                 MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
3124                 if (ms) {
3125                         ms->vca_assign (vca);
3126                 }
3127         }
3128 }
3129
3130 void
3131 Mixer_UI::vca_unassign (boost::shared_ptr<VCA> vca)
3132 {
3133         set_axis_targets_for_operation ();
3134         BOOST_FOREACH(AxisView* r, _axis_targets) {
3135                 MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
3136                 if (ms) {
3137                         ms->vca_unassign (vca);
3138                 }
3139         }
3140 }