Clarify my XML error printout from yesterday (see previous commit)
[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 <gtkmm/accelmap.h>
29
30 #include "pbd/convert.h"
31 #include "pbd/stacktrace.h"
32 #include "pbd/unwind.h"
33
34 #include <glibmm/threads.h>
35
36 #include <gtkmm2ext/gtk_ui.h>
37 #include <gtkmm2ext/keyboard.h>
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/tearoff.h>
40 #include <gtkmm2ext/window_title.h>
41 #include <gtkmm2ext/doi.h>
42
43 #include "ardour/amp.h"
44 #include "ardour/debug.h"
45 #include "ardour/midi_track.h"
46 #include "ardour/plugin_manager.h"
47 #include "ardour/route_group.h"
48 #include "ardour/route_sorters.h"
49 #include "ardour/session.h"
50
51 #include "keyboard.h"
52 #include "mixer_ui.h"
53 #include "mixer_strip.h"
54 #include "monitor_section.h"
55 #include "plugin_selector.h"
56 #include "public_editor.h"
57 #include "ardour_ui.h"
58 #include "prompter.h"
59 #include "utils.h"
60 #include "route_sorter.h"
61 #include "actions.h"
62 #include "gui_thread.h"
63 #include "mixer_group_tabs.h"
64 #include "timers.h"
65 #include "ui_config.h"
66
67 #include "i18n.h"
68
69 using namespace ARDOUR;
70 using namespace ARDOUR_UI_UTILS;
71 using namespace PBD;
72 using namespace Gtk;
73 using namespace Glib;
74 using namespace Gtkmm2ext;
75 using namespace std;
76
77 using PBD::atoi;
78 using PBD::Unwinder;
79
80 Mixer_UI* Mixer_UI::_instance = 0;
81
82 Mixer_UI*
83 Mixer_UI::instance ()
84 {
85         if (!_instance) {
86                 _instance  = new Mixer_UI;
87         }
88
89         return _instance;
90 }
91
92 Mixer_UI::Mixer_UI ()
93         : Tabbable (_content, _("Mixer"))
94         , no_track_list_redisplay (false)
95         , in_group_row_change (false)
96         , track_menu (0)
97         , _monitor_section (0)
98         , _plugin_selector (0)
99         , _strip_width (UIConfiguration::instance().get_default_narrow_ms() ? Narrow : Wide)
100         , ignore_reorder (false)
101         , _in_group_rebuild_or_clear (false)
102         , _route_deletion_in_progress (false)
103         , _following_editor_selection (false)
104         , _maximised (false)
105         , _show_mixer_list (true)
106 {
107         Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::sync_treeview_from_order_keys, this), gui_context());
108
109         /* bindings was already set in MixerActor constructor */
110
111         _content.set_data ("ardour-bindings", bindings);
112
113         scroller.set_can_default (true);
114         // set_default (scroller);
115
116         scroller_base.set_flags (Gtk::CAN_FOCUS);
117         scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
118         scroller_base.set_name ("MixerWindow");
119         scroller_base.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::strip_scroller_button_release));
120         // add as last item of strip packer
121         strip_packer.pack_end (scroller_base, true, true);
122
123         _group_tabs = new MixerGroupTabs (this);
124         VBox* b = manage (new VBox);
125         b->pack_start (*_group_tabs, PACK_SHRINK);
126         b->pack_start (strip_packer);
127         b->show_all ();
128
129         scroller.add (*b);
130         scroller.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC);
131
132         setup_track_display ();
133
134         group_model = ListStore::create (group_columns);
135         group_display.set_model (group_model);
136         group_display.append_column (_("Group"), group_columns.text);
137         group_display.append_column (_("Show"), group_columns.visible);
138         group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
139         group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
140         group_display.get_column (0)->set_expand(true);
141         group_display.get_column (1)->set_expand(false);
142         group_display.set_name ("EditGroupList");
143         group_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
144         group_display.set_reorderable (true);
145         group_display.set_headers_visible (true);
146         group_display.set_rules_hint (true);
147         group_display.set_can_focus(false);
148
149         /* name is directly editable */
150
151         CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
152         name_cell->property_editable() = true;
153         name_cell->signal_edited().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_name_edit));
154
155         /* use checkbox for the active column */
156
157         CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(group_display.get_column_cell_renderer (1));
158         active_cell->property_activatable() = true;
159         active_cell->property_radio() = false;
160
161         group_model->signal_row_changed().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_change));
162         /* We use this to notice drag-and-drop reorders of the group list */
163         group_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_deleted));
164         group_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::group_display_button_press), false);
165
166         group_display_scroller.add (group_display);
167         group_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
168
169         HBox* route_group_display_button_box = manage (new HBox());
170
171         Button* route_group_add_button = manage (new Button ());
172         Button* route_group_remove_button = manage (new Button ());
173
174         Widget* w;
175
176         w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
177         w->show();
178         route_group_add_button->add (*w);
179
180         w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
181         w->show();
182         route_group_remove_button->add (*w);
183
184         route_group_display_button_box->set_homogeneous (true);
185
186         route_group_add_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_route_group));
187         route_group_remove_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::remove_selected_route_group));
188
189         route_group_display_button_box->add (*route_group_add_button);
190         route_group_display_button_box->add (*route_group_remove_button);
191
192         group_display_vbox.pack_start (group_display_scroller, true, true);
193         group_display_vbox.pack_start (*route_group_display_button_box, false, false);
194
195         group_display_frame.set_name ("BaseFrame");
196         group_display_frame.set_shadow_type (Gtk::SHADOW_IN);
197         group_display_frame.add (group_display_vbox);
198
199         favorite_plugins_model = PluginTreeStore::create (favorite_plugins_columns);
200         favorite_plugins_display.set_model (favorite_plugins_model);
201         favorite_plugins_display.append_column (_("Favorite Plugins"), favorite_plugins_columns.name);
202         favorite_plugins_display.set_name ("EditGroupList");
203         favorite_plugins_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
204         favorite_plugins_display.set_reorderable (false);
205         favorite_plugins_display.set_headers_visible (true);
206         favorite_plugins_display.set_rules_hint (true);
207         favorite_plugins_display.set_can_focus (false);
208         favorite_plugins_display.add_object_drag (favorite_plugins_columns.plugin.index(), "PluginPresetPtr");
209         favorite_plugins_display.set_drag_column (favorite_plugins_columns.name.index());
210         favorite_plugins_display.signal_row_activated().connect (sigc::mem_fun (*this, &Mixer_UI::plugin_row_activated));
211         favorite_plugins_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::plugin_row_button_press), false);
212         favorite_plugins_display.signal_drop.connect (sigc::mem_fun (*this, &Mixer_UI::plugin_drop));
213         favorite_plugins_display.signal_row_expanded().connect (sigc::mem_fun (*this, &Mixer_UI::save_favorite_ui_state));
214         favorite_plugins_display.signal_row_collapsed().connect (sigc::mem_fun (*this, &Mixer_UI::save_favorite_ui_state));
215         favorite_plugins_model->signal_row_has_child_toggled().connect (sigc::mem_fun (*this, &Mixer_UI::sync_treeview_favorite_ui_state));
216
217         favorite_plugins_scroller.add (favorite_plugins_display);
218         favorite_plugins_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
219
220         favorite_plugins_frame.set_name ("BaseFrame");
221         favorite_plugins_frame.set_shadow_type (Gtk::SHADOW_IN);
222         favorite_plugins_frame.add (favorite_plugins_scroller);
223
224         rhs_pane1.pack1 (favorite_plugins_frame, false, true);
225         rhs_pane1.pack2 (track_display_frame);
226         rhs_pane2.pack1 (rhs_pane1);
227         rhs_pane2.pack2 (group_display_frame);
228
229         list_vpacker.pack_start (rhs_pane2, true, true);
230
231         global_hpacker.pack_start (scroller, true, true);
232         global_hpacker.pack_start (out_packer, false, false);
233
234         list_hpane.pack1(list_vpacker, false, true);
235         list_hpane.pack2(global_hpacker, true, false);
236
237         rhs_pane1.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
238                                                         static_cast<Gtk::Paned*> (&rhs_pane1)));
239         rhs_pane2.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
240                                                         static_cast<Gtk::Paned*> (&rhs_pane2)));
241         list_hpane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
242                                                          static_cast<Gtk::Paned*> (&list_hpane)));
243
244         _content.pack_start (list_hpane, true, true);
245
246         update_title ();
247
248         route_group_display_button_box->show();
249         route_group_add_button->show();
250         route_group_remove_button->show();
251
252         _content.show ();
253         _content.set_name ("MixerWindow");
254
255         global_hpacker.show();
256         scroller.show();
257         scroller_base.show();
258         scroller_hpacker.show();
259         mixer_scroller_vpacker.show();
260         list_vpacker.show();
261         group_display_button_label.show();
262         group_display_button.show();
263         group_display_scroller.show();
264         favorite_plugins_scroller.show();
265         group_display_vbox.show();
266         group_display_frame.show();
267         favorite_plugins_frame.show();
268         rhs_pane1.show();
269         rhs_pane2.show();
270         strip_packer.show();
271         out_packer.show();
272         list_hpane.show();
273         group_display.show();
274         favorite_plugins_display.show();
275
276         MixerStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_strip, this, _1), gui_context());
277
278 #ifndef DEFER_PLUGIN_SELECTOR_LOAD
279         _plugin_selector = new PluginSelector (PluginManager::instance ());
280 #else
281 #error implement deferred Plugin-Favorite list
282 #endif
283         PluginManager::instance ().PluginListChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context());
284         PluginManager::instance ().PluginStatusesChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context());
285         ARDOUR::Plugin::PresetsChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context());
286 }
287
288 Mixer_UI::~Mixer_UI ()
289 {
290         if (_monitor_section) {
291                 monitor_section_detached ();
292                 delete _monitor_section;
293         }
294         delete _plugin_selector;
295 }
296
297 void
298 Mixer_UI::track_editor_selection ()
299 {
300         PublicEditor::instance().get_selection().TracksChanged.connect (sigc::mem_fun (*this, &Mixer_UI::follow_editor_selection));
301 }
302
303 Gtk::Window*
304 Mixer_UI::use_own_window (bool and_fill_it)
305 {
306         bool new_window = !own_window();
307
308         Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
309
310
311         if (win && new_window) {
312                 win->set_name ("MixerWindow");
313                 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Mixer"), this);
314                 win->signal_scroll_event().connect (sigc::mem_fun (*this, &Mixer_UI::on_scroll_event), false);
315                 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
316                 win->set_data ("ardour-bindings", bindings);
317                 update_title ();
318         }
319
320         return win;
321 }
322
323 void
324 Mixer_UI::show_window ()
325 {
326         Tabbable::show_window ();
327
328         /* show/hide group tabs as required */
329         parameter_changed ("show-group-tabs");
330
331         /* now reset each strips width so the right widgets are shown */
332         MixerStrip* ms;
333
334         TreeModel::Children rows = track_model->children();
335         TreeModel::Children::iterator ri;
336
337         for (ri = rows.begin(); ri != rows.end(); ++ri) {
338                 ms = (*ri)[track_columns.strip];
339                 ms->set_width_enum (ms->get_width_enum (), ms->width_owner());
340                 /* Fix visibility of mixer strip stuff */
341                 ms->parameter_changed (X_("mixer-element-visibility"));
342         }
343
344         /* force focus into main area */
345         scroller_base.grab_focus ();
346 }
347
348 void
349 Mixer_UI::add_strips (RouteList& routes)
350 {
351         bool from_scratch = track_model->children().size() == 0;
352         Gtk::TreeModel::Children::iterator insert_iter = track_model->children().end();
353
354         for (Gtk::TreeModel::Children::iterator it = track_model->children().begin(); it != track_model->children().end(); ++it) {
355                 boost::shared_ptr<Route> r = (*it)[track_columns.route];
356
357                 if (r->order_key() == (routes.front()->order_key() + routes.size())) {
358                         insert_iter = it;
359                         break;
360                 }
361         }
362
363         if(!from_scratch) {
364                 _selection.clear_routes ();
365         }
366
367         MixerStrip* strip;
368
369         try {
370                 no_track_list_redisplay = true;
371                 track_display.set_model (Glib::RefPtr<ListStore>());
372
373                 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
374                         boost::shared_ptr<Route> route = (*x);
375
376                         if (route->is_auditioner()) {
377                                 continue;
378                         }
379
380                         if (route->is_monitor()) {
381
382                                 if (!_monitor_section) {
383                                         _monitor_section = new MonitorSection (_session);
384
385                                         XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
386                                         if (mnode) {
387                                                 _monitor_section->tearoff().set_state (*mnode);
388                                         }
389                                 }
390
391                                 out_packer.pack_end (_monitor_section->tearoff(), false, false);
392                                 _monitor_section->set_session (_session);
393                                 _monitor_section->tearoff().show_all ();
394
395                                 _monitor_section->tearoff().Detach.connect (sigc::mem_fun(*this, &Mixer_UI::monitor_section_detached));
396                                 _monitor_section->tearoff().Attach.connect (sigc::mem_fun(*this, &Mixer_UI::monitor_section_attached));
397
398                                 monitor_section_attached ();
399
400                                 route->DropReferences.connect (*this, invalidator(*this), boost::bind (&Mixer_UI::monitor_section_going_away, this), gui_context());
401
402                                 /* no regular strip shown for control out */
403
404                                 continue;
405                         }
406
407                         strip = new MixerStrip (*this, _session, route);
408                         strips.push_back (strip);
409
410                         UIConfiguration::instance().get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide;
411
412                         if (strip->width_owner() != strip) {
413                                 strip->set_width_enum (_strip_width, this);
414                         }
415
416                         show_strip (strip);
417
418                         TreeModel::Row row = *(track_model->insert(insert_iter));
419                         row[track_columns.text] = route->name();
420                         row[track_columns.visible] = strip->route()->is_master() ? true : strip->marked_for_display();
421                         row[track_columns.route] = route;
422                         row[track_columns.strip] = strip;
423
424                         if (!from_scratch) {
425                                 _selection.add (strip);
426                         }
427
428                         route->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::strip_property_changed, this, _1, strip), gui_context());
429
430                         strip->WidthChanged.connect (sigc::mem_fun(*this, &Mixer_UI::strip_width_changed));
431                         strip->signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::strip_button_release_event), strip));
432                 }
433
434         } catch (const std::exception& e) {
435                 error << string_compose (_("Error adding GUI elements for new tracks/busses %1"), e.what()) << endmsg;
436         }
437
438         no_track_list_redisplay = false;
439         track_display.set_model (track_model);
440
441         sync_order_keys_from_treeview ();
442         redisplay_track_list ();
443 }
444
445 void
446 Mixer_UI::deselect_all_strip_processors ()
447 {
448         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
449                 (*i)->deselect_all_processors();
450         }
451 }
452
453 void
454 Mixer_UI::select_none ()
455 {
456         _selection.clear_routes();
457         deselect_all_strip_processors();
458 }
459
460 void
461 Mixer_UI::delete_processors ()
462 {
463         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
464                 (*i)->delete_processors();
465         }
466 }
467
468
469 void
470 Mixer_UI::remove_strip (MixerStrip* strip)
471 {
472         if (_session && _session->deletion_in_progress()) {
473                 /* its all being taken care of */
474                 return;
475         }
476
477         TreeModel::Children rows = track_model->children();
478         TreeModel::Children::iterator ri;
479         list<MixerStrip *>::iterator i;
480
481         if ((i = find (strips.begin(), strips.end(), strip)) != strips.end()) {
482                 strips.erase (i);
483         }
484
485         for (ri = rows.begin(); ri != rows.end(); ++ri) {
486                 if ((*ri)[track_columns.strip] == strip) {
487                         PBD::Unwinder<bool> uw (_route_deletion_in_progress, true);
488                         track_model->erase (ri);
489                         break;
490                 }
491         }
492 }
493
494 void
495 Mixer_UI::reset_remote_control_ids ()
496 {
497         if (Config->get_remote_model() == UserOrdered || !_session || _session->deletion_in_progress()) {
498                 return;
499         }
500
501         TreeModel::Children rows = track_model->children();
502
503         if (rows.empty()) {
504                 return;
505         }
506
507         DEBUG_TRACE (DEBUG::OrderKeys, "mixer resets remote control ids after remote model change\n");
508
509         TreeModel::Children::iterator ri;
510         bool rid_change = false;
511         uint32_t rid = 1;
512         uint32_t invisible_key = UINT32_MAX;
513
514         for (ri = rows.begin(); ri != rows.end(); ++ri) {
515
516                 /* skip two special values */
517
518                 if (rid == Route::MasterBusRemoteControlID) {
519                         rid++;
520                 }
521
522                 if (rid == Route::MonitorBusRemoteControlID) {
523                         rid++;
524                 }
525
526                 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
527                 bool visible = (*ri)[track_columns.visible];
528
529                 if (!route->is_master() && !route->is_monitor()) {
530
531                         uint32_t new_rid = (visible ? rid : invisible_key--);
532
533                         if (new_rid != route->remote_control_id()) {
534                                 route->set_remote_control_id_explicit (new_rid);
535                                 rid_change = true;
536                         }
537
538                         if (visible) {
539                                 rid++;
540                         }
541                 }
542         }
543
544         if (rid_change) {
545                 /* tell the world that we changed the remote control IDs */
546                 _session->notify_remote_id_change ();
547         }
548 }
549
550 void
551 Mixer_UI::sync_order_keys_from_treeview ()
552 {
553         if (ignore_reorder || !_session || _session->deletion_in_progress()) {
554                 return;
555         }
556
557         TreeModel::Children rows = track_model->children();
558
559         if (rows.empty()) {
560                 return;
561         }
562
563         DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync order keys from model\n");
564
565         TreeModel::Children::iterator ri;
566         bool changed = false;
567         bool rid_change = false;
568         uint32_t order = 0;
569         uint32_t rid = 1;
570         uint32_t invisible_key = UINT32_MAX;
571
572         for (ri = rows.begin(); ri != rows.end(); ++ri) {
573                 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
574                 bool visible = (*ri)[track_columns.visible];
575
576                 uint32_t old_key = route->order_key ();
577
578                 if (order != old_key) {
579                         route->set_order_key (order);
580                         changed = true;
581                 }
582
583                 if ((Config->get_remote_model() == MixerOrdered) && !route->is_master() && !route->is_monitor()) {
584
585                         uint32_t new_rid = (visible ? rid : invisible_key--);
586
587                         if (new_rid != route->remote_control_id()) {
588                                 route->set_remote_control_id_explicit (new_rid);
589                                 rid_change = true;
590                         }
591
592                         if (visible) {
593                                 rid++;
594                         }
595
596                 }
597
598                 ++order;
599         }
600
601         if (changed) {
602                 /* tell everyone that we changed the mixer sort keys */
603                 _session->sync_order_keys ();
604         }
605
606         if (rid_change) {
607                 /* tell the world that we changed the remote control IDs */
608                 _session->notify_remote_id_change ();
609         }
610 }
611
612 void
613 Mixer_UI::sync_treeview_from_order_keys ()
614 {
615         if (!_session || _session->deletion_in_progress()) {
616                 return;
617         }
618
619         DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync model from order keys.\n");
620
621         /* we could get here after either a change in the Mixer or Editor sort
622          * order, but either way, the mixer order keys reflect the intended
623          * order for the GUI, so reorder the treeview model to match it.
624          */
625
626         vector<int> neworder;
627         TreeModel::Children rows = track_model->children();
628         uint32_t old_order = 0;
629         bool changed = false;
630
631         if (rows.empty()) {
632                 return;
633         }
634
635         OrderKeySortedRoutes sorted_routes;
636
637         for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
638                 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
639                 sorted_routes.push_back (RoutePlusOrderKey (route, old_order, route->order_key ()));
640         }
641
642         SortByNewDisplayOrder cmp;
643
644         sort (sorted_routes.begin(), sorted_routes.end(), cmp);
645         neworder.assign (sorted_routes.size(), 0);
646
647         uint32_t n = 0;
648
649         for (OrderKeySortedRoutes::iterator sr = sorted_routes.begin(); sr != sorted_routes.end(); ++sr, ++n) {
650
651                 neworder[n] = sr->old_display_order;
652
653                 if (sr->old_display_order != n) {
654                         changed = true;
655                 }
656
657                 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("MIXER change order for %1 from %2 to %3\n",
658                                                                sr->route->name(), sr->old_display_order, n));
659         }
660
661         if (changed) {
662                 Unwinder<bool> uw (ignore_reorder, true);
663                 track_model->reorder (neworder);
664         }
665
666         redisplay_track_list ();
667 }
668
669 void
670 Mixer_UI::follow_editor_selection ()
671 {
672         if (_following_editor_selection) {
673                 return;
674         }
675
676         _following_editor_selection = true;
677         _selection.block_routes_changed (true);
678
679         TrackSelection& s (PublicEditor::instance().get_selection().tracks);
680
681         _selection.clear_routes ();
682
683         for (TrackViewList::iterator i = s.begin(); i != s.end(); ++i) {
684                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*i);
685                 if (rtav) {
686                         MixerStrip* ms = strip_by_route (rtav->route());
687                         if (ms) {
688                                 _selection.add (ms);
689                         }
690                 }
691         }
692
693         _following_editor_selection = false;
694         _selection.block_routes_changed (false);
695 }
696
697
698 MixerStrip*
699 Mixer_UI::strip_by_route (boost::shared_ptr<Route> r)
700 {
701         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
702                 if ((*i)->route() == r) {
703                         return (*i);
704                 }
705         }
706
707         return 0;
708 }
709
710 bool
711 Mixer_UI::strip_button_release_event (GdkEventButton *ev, MixerStrip *strip)
712 {
713         if (ev->button == 1) {
714                 if (_selection.selected (strip)) {
715                         /* primary-click: toggle selection state of strip */
716                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
717                                 _selection.remove (strip);
718                         } else if (_selection.routes.size() > 1) {
719                                 /* de-select others */
720                                 _selection.set (strip);
721                         }
722                 } else {
723                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
724                                 _selection.add (strip);
725                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::RangeSelectModifier)) {
726
727                                 if (!_selection.selected(strip)) {
728
729                                         /* extend selection */
730
731                                         vector<MixerStrip*> tmp;
732                                         bool accumulate = false;
733                                         bool found_another = false;
734
735                                         tmp.push_back (strip);
736
737                                         for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
738                                                 if ((*i) == strip) {
739                                                         /* hit clicked strip, start accumulating till we hit the first
740                                                            selected strip
741                                                         */
742                                                         if (accumulate) {
743                                                                 /* done */
744                                                                 break;
745                                                         } else {
746                                                                 accumulate = true;
747                                                         }
748                                                 } else if (_selection.selected (*i)) {
749                                                         /* hit selected strip. if currently accumulating others,
750                                                            we're done. if not accumulating others, start doing so.
751                                                         */
752                                                         found_another = true;
753                                                         if (accumulate) {
754                                                                 /* done */
755                                                                 break;
756                                                         } else {
757                                                                 accumulate = true;
758                                                         }
759                                                 } else {
760                                                         if (accumulate) {
761                                                                 tmp.push_back (*i);
762                                                         }
763                                                 }
764                                         }
765
766                                         if (found_another) {
767                                                 for (vector<MixerStrip*>::iterator i = tmp.begin(); i != tmp.end(); ++i) {
768                                                         _selection.add (*i);
769                                                 }
770                                         } else
771                                                 _selection.set (strip);  //user wants to start a range selection, but there aren't any others selected yet
772                                 }
773
774                         } else {
775                                 _selection.set (strip);
776                         }
777                 }
778         }
779
780         return true;
781 }
782
783 void
784 Mixer_UI::set_session (Session* sess)
785 {
786         SessionHandlePtr::set_session (sess);
787
788         if (_plugin_selector) {
789                 _plugin_selector->set_session (_session);
790         }
791
792         _group_tabs->set_session (sess);
793
794         if (!_session) {
795                 return;
796         }
797
798         refill_favorite_plugins();
799
800         XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
801         set_state (*node, 0);
802
803         update_title ();
804
805         initial_track_display ();
806
807         _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_strips, this, _1), gui_context());
808         _session->route_group_added.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_route_group, this, _1), gui_context());
809         _session->route_group_removed.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
810         _session->route_groups_reordered.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
811         _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::parameter_changed, this, _1), gui_context());
812         _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::update_title, this), gui_context());
813         _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::update_title, this), gui_context());
814
815         Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::parameter_changed, this, _1), gui_context ());
816
817         route_groups_changed ();
818
819         if (_visible) {
820                 show_window();
821         }
822         start_updating ();
823 }
824
825 void
826 Mixer_UI::session_going_away ()
827 {
828         ENSURE_GUI_THREAD (*this, &Mixer_UI::session_going_away);
829
830         _in_group_rebuild_or_clear = true;
831         group_model->clear ();
832         _in_group_rebuild_or_clear = false;
833
834         _selection.clear ();
835         track_model->clear ();
836
837         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
838                 delete (*i);
839         }
840
841         if (_monitor_section) {
842                 _monitor_section->tearoff().hide_visible ();
843         }
844
845         monitor_section_detached ();
846
847         strips.clear ();
848
849         stop_updating ();
850
851         SessionHandlePtr::session_going_away ();
852
853         _session = 0;
854         update_title ();
855 }
856
857 void
858 Mixer_UI::track_visibility_changed (std::string const & path)
859 {
860         if (_session && _session->deletion_in_progress()) {
861                 return;
862         }
863
864         TreeIter iter;
865
866         if ((iter = track_model->get_iter (path))) {
867                 MixerStrip* strip = (*iter)[track_columns.strip];
868                 if (strip) {
869                         bool visible = (*iter)[track_columns.visible];
870
871                         if (strip->set_marked_for_display (!visible)) {
872                                 update_track_visibility ();
873                         }
874                 }
875         }
876 }
877
878 void
879 Mixer_UI::update_track_visibility ()
880 {
881         TreeModel::Children rows = track_model->children();
882         TreeModel::Children::iterator i;
883
884         {
885                 Unwinder<bool> uw (no_track_list_redisplay, true);
886
887                 for (i = rows.begin(); i != rows.end(); ++i) {
888                         MixerStrip *strip = (*i)[track_columns.strip];
889                         (*i)[track_columns.visible] = strip->marked_for_display ();
890                 }
891
892                 /* force route order keys catch up with visibility changes
893                  */
894
895                 sync_order_keys_from_treeview ();
896         }
897
898         redisplay_track_list ();
899 }
900
901 void
902 Mixer_UI::show_strip (MixerStrip* ms)
903 {
904         TreeModel::Children rows = track_model->children();
905         TreeModel::Children::iterator i;
906
907         for (i = rows.begin(); i != rows.end(); ++i) {
908
909                 MixerStrip* strip = (*i)[track_columns.strip];
910                 if (strip == ms) {
911                         (*i)[track_columns.visible] = true;
912                         redisplay_track_list ();
913                         break;
914                 }
915         }
916 }
917
918 void
919 Mixer_UI::hide_strip (MixerStrip* ms)
920 {
921         TreeModel::Children rows = track_model->children();
922         TreeModel::Children::iterator i;
923
924         for (i = rows.begin(); i != rows.end(); ++i) {
925
926                 MixerStrip* strip = (*i)[track_columns.strip];
927                 if (strip == ms) {
928                         (*i)[track_columns.visible] = false;
929                         redisplay_track_list ();
930                         break;
931                 }
932         }
933 }
934
935 gint
936 Mixer_UI::start_updating ()
937 {
938     fast_screen_update_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &Mixer_UI::fast_update_strips));
939     return 0;
940 }
941
942 gint
943 Mixer_UI::stop_updating ()
944 {
945     fast_screen_update_connection.disconnect();
946     return 0;
947 }
948
949 void
950 Mixer_UI::fast_update_strips ()
951 {
952         if (_content.is_mapped () && _session) {
953                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
954                         (*i)->fast_update ();
955                 }
956         }
957 }
958
959 void
960 Mixer_UI::set_all_strips_visibility (bool yn)
961 {
962         TreeModel::Children rows = track_model->children();
963         TreeModel::Children::iterator i;
964
965         {
966                 Unwinder<bool> uw (no_track_list_redisplay, true);
967
968                 for (i = rows.begin(); i != rows.end(); ++i) {
969
970                         TreeModel::Row row = (*i);
971                         MixerStrip* strip = row[track_columns.strip];
972
973                         if (strip == 0) {
974                                 continue;
975                         }
976
977                         if (strip->route()->is_master() || strip->route()->is_monitor()) {
978                                 continue;
979                         }
980
981                         (*i)[track_columns.visible] = yn;
982                 }
983         }
984
985         redisplay_track_list ();
986 }
987
988
989 void
990 Mixer_UI::set_all_audio_midi_visibility (int tracks, bool yn)
991 {
992         TreeModel::Children rows = track_model->children();
993         TreeModel::Children::iterator i;
994
995         {
996                 Unwinder<bool> uw (no_track_list_redisplay, true);
997
998                 for (i = rows.begin(); i != rows.end(); ++i) {
999                         TreeModel::Row row = (*i);
1000                         MixerStrip* strip = row[track_columns.strip];
1001
1002                         if (strip == 0) {
1003                                 continue;
1004                         }
1005
1006                         if (strip->route()->is_master() || strip->route()->is_monitor()) {
1007                                 continue;
1008                         }
1009
1010                         boost::shared_ptr<AudioTrack> at = strip->audio_track();
1011                         boost::shared_ptr<MidiTrack> mt = strip->midi_track();
1012
1013                         switch (tracks) {
1014                         case 0:
1015                                 (*i)[track_columns.visible] = yn;
1016                                 break;
1017
1018                         case 1:
1019                                 if (at) { /* track */
1020                                         (*i)[track_columns.visible] = yn;
1021                                 }
1022                                 break;
1023
1024                         case 2:
1025                                 if (!at && !mt) { /* bus */
1026                                         (*i)[track_columns.visible] = yn;
1027                                 }
1028                                 break;
1029
1030                         case 3:
1031                                 if (mt) { /* midi-track */
1032                                         (*i)[track_columns.visible] = yn;
1033                                 }
1034                                 break;
1035                         }
1036                 }
1037         }
1038
1039         redisplay_track_list ();
1040 }
1041
1042 void
1043 Mixer_UI::hide_all_routes ()
1044 {
1045         set_all_strips_visibility (false);
1046 }
1047
1048 void
1049 Mixer_UI::show_all_routes ()
1050 {
1051         set_all_strips_visibility (true);
1052 }
1053
1054 void
1055 Mixer_UI::show_all_audiobus ()
1056 {
1057         set_all_audio_midi_visibility (2, true);
1058 }
1059 void
1060 Mixer_UI::hide_all_audiobus ()
1061 {
1062         set_all_audio_midi_visibility (2, false);
1063 }
1064
1065 void
1066 Mixer_UI::show_all_audiotracks()
1067 {
1068         set_all_audio_midi_visibility (1, true);
1069 }
1070 void
1071 Mixer_UI::hide_all_audiotracks ()
1072 {
1073         set_all_audio_midi_visibility (1, false);
1074 }
1075
1076 void
1077 Mixer_UI::show_all_miditracks()
1078 {
1079         set_all_audio_midi_visibility (3, true);
1080 }
1081 void
1082 Mixer_UI::hide_all_miditracks ()
1083 {
1084         set_all_audio_midi_visibility (3, false);
1085 }
1086
1087
1088 void
1089 Mixer_UI::track_list_reorder (const TreeModel::Path&, const TreeModel::iterator&, int* /*new_order*/)
1090 {
1091         DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview reordered\n");
1092         sync_order_keys_from_treeview ();
1093 }
1094
1095 void
1096 Mixer_UI::track_list_delete (const Gtk::TreeModel::Path&)
1097 {
1098         /* this happens as the second step of a DnD within the treeview as well
1099            as when a row/route is actually deleted.
1100
1101            if it was a deletion then we have to force a redisplay because
1102            order keys may not have changed.
1103         */
1104
1105         DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview row deleted\n");
1106         sync_order_keys_from_treeview ();
1107
1108         if (_route_deletion_in_progress) {
1109                 redisplay_track_list ();
1110         }
1111 }
1112
1113 void
1114 Mixer_UI::redisplay_track_list ()
1115 {
1116         TreeModel::Children rows = track_model->children();
1117         TreeModel::Children::iterator i;
1118
1119         if (no_track_list_redisplay) {
1120                 return;
1121         }
1122
1123         for (i = rows.begin(); i != rows.end(); ++i) {
1124
1125                 MixerStrip* strip = (*i)[track_columns.strip];
1126
1127                 if (strip == 0) {
1128                         /* we're in the middle of changing a row, don't worry */
1129                         continue;
1130                 }
1131
1132                 bool const visible = (*i)[track_columns.visible];
1133
1134                 if (visible) {
1135                         strip->set_gui_property ("visible", true);
1136
1137                         if (strip->packed()) {
1138
1139                                 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1140                                         out_packer.reorder_child (*strip, -1);
1141
1142                                 } else {
1143                                         strip_packer.reorder_child (*strip, -1); /* put at end */
1144                                 }
1145
1146                         } else {
1147
1148                                 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1149                                         out_packer.pack_start (*strip, false, false);
1150                                 } else {
1151                                         strip_packer.pack_start (*strip, false, false);
1152                                 }
1153                                 strip->set_packed (true);
1154                         }
1155
1156                 } else {
1157
1158                         strip->set_gui_property ("visible", false);
1159
1160                         if (strip->route()->is_master() || strip->route()->is_monitor()) {
1161                                 /* do nothing, these cannot be hidden */
1162                         } else {
1163                                 if (strip->packed()) {
1164                                         strip_packer.remove (*strip);
1165                                         strip->set_packed (false);
1166                                 }
1167                         }
1168                 }
1169         }
1170
1171         _group_tabs->set_dirty ();
1172 }
1173
1174 void
1175 Mixer_UI::strip_width_changed ()
1176 {
1177         _group_tabs->set_dirty ();
1178
1179 #ifdef __APPLE__
1180         TreeModel::Children rows = track_model->children();
1181         TreeModel::Children::iterator i;
1182         long order;
1183
1184         for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
1185                 MixerStrip* strip = (*i)[track_columns.strip];
1186
1187                 if (strip == 0) {
1188                         continue;
1189                 }
1190
1191                 bool visible = (*i)[track_columns.visible];
1192
1193                 if (visible) {
1194                         strip->queue_draw();
1195                 }
1196         }
1197 #endif
1198
1199 }
1200
1201 void
1202 Mixer_UI::initial_track_display ()
1203 {
1204         boost::shared_ptr<RouteList> routes = _session->get_routes();
1205         RouteList copy (*routes);
1206         ARDOUR::SignalOrderRouteSorter sorter;
1207
1208         copy.sort (sorter);
1209
1210         {
1211                 Unwinder<bool> uw1 (no_track_list_redisplay, true);
1212                 Unwinder<bool> uw2 (ignore_reorder, true);
1213
1214                 track_model->clear ();
1215                 add_strips (copy);
1216         }
1217
1218         _session->sync_order_keys ();
1219
1220         redisplay_track_list ();
1221 }
1222
1223 void
1224 Mixer_UI::show_track_list_menu ()
1225 {
1226         if (track_menu == 0) {
1227                 build_track_menu ();
1228         }
1229
1230         track_menu->popup (1, gtk_get_current_event_time());
1231 }
1232
1233 bool
1234 Mixer_UI::track_display_button_press (GdkEventButton* ev)
1235 {
1236         if (Keyboard::is_context_menu_event (ev)) {
1237                 show_track_list_menu ();
1238                 return true;
1239         }
1240
1241         return false;
1242 }
1243
1244 void
1245 Mixer_UI::build_track_menu ()
1246 {
1247         using namespace Menu_Helpers;
1248         using namespace Gtk;
1249
1250         track_menu = new Menu;
1251         track_menu->set_name ("ArdourContextMenu");
1252         MenuList& items = track_menu->items();
1253
1254         items.push_back (MenuElem (_("Show All"), sigc::mem_fun(*this, &Mixer_UI::show_all_routes)));
1255         items.push_back (MenuElem (_("Hide All"), sigc::mem_fun(*this, &Mixer_UI::hide_all_routes)));
1256         items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
1257         items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
1258         items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus)));
1259         items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
1260         items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &Mixer_UI::show_all_miditracks)));
1261         items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &Mixer_UI::hide_all_miditracks)));
1262
1263 }
1264
1265 void
1266 Mixer_UI::strip_property_changed (const PropertyChange& what_changed, MixerStrip* mx)
1267 {
1268         if (!what_changed.contains (ARDOUR::Properties::name)) {
1269                 return;
1270         }
1271
1272         ENSURE_GUI_THREAD (*this, &Mixer_UI::strip_name_changed, what_changed, mx)
1273
1274         TreeModel::Children rows = track_model->children();
1275         TreeModel::Children::iterator i;
1276
1277         for (i = rows.begin(); i != rows.end(); ++i) {
1278                 if ((*i)[track_columns.strip] == mx) {
1279                         (*i)[track_columns.text] = mx->route()->name();
1280                         return;
1281                 }
1282         }
1283
1284         error << _("track display list item for renamed strip not found!") << endmsg;
1285 }
1286
1287 bool
1288 Mixer_UI::group_display_button_press (GdkEventButton* ev)
1289 {
1290         TreeModel::Path path;
1291         TreeViewColumn* column;
1292         int cellx;
1293         int celly;
1294
1295         if (!group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
1296                 _group_tabs->get_menu(0)->popup (1, ev->time);
1297                 return true;
1298         }
1299
1300         TreeIter iter = group_model->get_iter (path);
1301         if (!iter) {
1302                 _group_tabs->get_menu(0)->popup (1, ev->time);
1303                 return true;
1304         }
1305
1306         RouteGroup* group = (*iter)[group_columns.group];
1307
1308         if (Keyboard::is_context_menu_event (ev)) {
1309                 _group_tabs->get_menu(group)->popup (1, ev->time);
1310                 return true;
1311         }
1312
1313         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
1314         case 0:
1315                 if (Keyboard::is_edit_event (ev)) {
1316                         if (group) {
1317                                 // edit_route_group (group);
1318 #ifdef __APPLE__
1319                                 group_display.queue_draw();
1320 #endif
1321                                 return true;
1322                         }
1323                 }
1324                 break;
1325
1326         case 1:
1327         {
1328                 bool visible = (*iter)[group_columns.visible];
1329                 (*iter)[group_columns.visible] = !visible;
1330 #ifdef __APPLE__
1331                 group_display.queue_draw();
1332 #endif
1333                 return true;
1334         }
1335
1336         default:
1337                 break;
1338         }
1339
1340         return false;
1341  }
1342
1343 void
1344 Mixer_UI::activate_all_route_groups ()
1345 {
1346         _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), true));
1347 }
1348
1349 void
1350 Mixer_UI::disable_all_route_groups ()
1351 {
1352         _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), false));
1353 }
1354
1355 void
1356 Mixer_UI::route_groups_changed ()
1357 {
1358         ENSURE_GUI_THREAD (*this, &Mixer_UI::route_groups_changed);
1359
1360         _in_group_rebuild_or_clear = true;
1361
1362         /* just rebuild the while thing */
1363
1364         group_model->clear ();
1365
1366 #if 0
1367         /* this is currently not used,
1368          * Mixer_UI::group_display_button_press() has a case for it,
1369          * and a commented edit_route_group() but that's n/a since 2011.
1370          *
1371          * This code is left as reminder that
1372          * row[group_columns.group] = 0 has special meaning.
1373          */
1374         {
1375                 TreeModel::Row row;
1376                 row = *(group_model->append());
1377                 row[group_columns.visible] = true;
1378                 row[group_columns.text] = (_("-all-"));
1379                 row[group_columns.group] = 0;
1380         }
1381 #endif
1382
1383         _session->foreach_route_group (sigc::mem_fun (*this, &Mixer_UI::add_route_group));
1384
1385         _group_tabs->set_dirty ();
1386         _in_group_rebuild_or_clear = false;
1387 }
1388
1389 void
1390 Mixer_UI::new_route_group ()
1391 {
1392         RouteList rl;
1393
1394         _group_tabs->run_new_group_dialog (rl);
1395 }
1396
1397 void
1398 Mixer_UI::remove_selected_route_group ()
1399 {
1400         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1401         TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1402
1403         if (rows.empty()) {
1404                 return;
1405         }
1406
1407         TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1408         TreeIter iter;
1409
1410         /* selection mode is single, so rows.begin() is it */
1411
1412         if ((iter = group_model->get_iter (*i))) {
1413
1414                 RouteGroup* rg = (*iter)[group_columns.group];
1415
1416                 if (rg) {
1417                         _session->remove_route_group (*rg);
1418                 }
1419         }
1420 }
1421
1422 void
1423 Mixer_UI::route_group_property_changed (RouteGroup* group, const PropertyChange& change)
1424 {
1425         if (in_group_row_change) {
1426                 return;
1427         }
1428
1429         /* force an update of any mixer strips that are using this group,
1430            otherwise mix group names don't change in mixer strips
1431         */
1432
1433         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1434                 if ((*i)->route_group() == group) {
1435                         (*i)->route_group_changed();
1436                 }
1437         }
1438
1439         TreeModel::iterator i;
1440         TreeModel::Children rows = group_model->children();
1441         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1442
1443         in_group_row_change = true;
1444
1445         for (i = rows.begin(); i != rows.end(); ++i) {
1446                 if ((*i)[group_columns.group] == group) {
1447                         (*i)[group_columns.visible] = !group->is_hidden ();
1448                         (*i)[group_columns.text] = group->name ();
1449                         break;
1450                 }
1451         }
1452
1453         in_group_row_change = false;
1454
1455         if (change.contains (Properties::name)) {
1456                 _group_tabs->set_dirty ();
1457         }
1458
1459         for (list<MixerStrip*>::iterator j = strips.begin(); j != strips.end(); ++j) {
1460                 if ((*j)->route_group() == group) {
1461                         if (group->is_hidden ()) {
1462                                 hide_strip (*j);
1463                         } else {
1464                                 show_strip (*j);
1465                         }
1466                 }
1467         }
1468 }
1469
1470 void
1471 Mixer_UI::show_mixer_list (bool yn)
1472 {
1473         if (yn) {
1474                 list_vpacker.show ();
1475
1476                 //if user wants to show the pane, we should make sure that it is wide enough to be visible
1477                 int width = list_hpane.get_position();
1478                 if (width < 40)
1479                         list_hpane.set_position(40);
1480         } else {
1481                 list_vpacker.hide ();
1482         }
1483
1484         _show_mixer_list = yn;
1485 }
1486
1487 void
1488 Mixer_UI::show_monitor_section (bool yn)
1489 {
1490         if (!monitor_section()) {
1491                 return;
1492         }
1493         if (monitor_section()->tearoff().torn_off()) {
1494                 return;
1495         }
1496
1497         if (yn) {
1498                 monitor_section()->tearoff().show();
1499         } else {
1500                 monitor_section()->tearoff().hide();
1501         }
1502 }
1503
1504 void
1505 Mixer_UI::route_group_name_edit (const std::string& path, const std::string& new_text)
1506 {
1507         RouteGroup* group;
1508         TreeIter iter;
1509
1510         if ((iter = group_model->get_iter (path))) {
1511
1512                 if ((group = (*iter)[group_columns.group]) == 0) {
1513                         return;
1514                 }
1515
1516                 if (new_text != group->name()) {
1517                         group->set_name (new_text);
1518                 }
1519         }
1520 }
1521
1522 void
1523 Mixer_UI::route_group_row_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator& iter)
1524 {
1525         RouteGroup* group;
1526
1527         if (in_group_row_change) {
1528                 return;
1529         }
1530
1531         if ((group = (*iter)[group_columns.group]) == 0) {
1532                 return;
1533         }
1534
1535         std::string name = (*iter)[group_columns.text];
1536
1537         if (name != group->name()) {
1538                 group->set_name (name);
1539         }
1540
1541         bool hidden = !(*iter)[group_columns.visible];
1542
1543         if (hidden != group->is_hidden ()) {
1544                 group->set_hidden (hidden, this);
1545         }
1546 }
1547
1548 /** Called when a group model row is deleted, but also when the model is
1549  *  reordered by a user drag-and-drop; the latter is what we are
1550  *  interested in here.
1551  */
1552 void
1553 Mixer_UI::route_group_row_deleted (Gtk::TreeModel::Path const &)
1554 {
1555         if (_in_group_rebuild_or_clear) {
1556                 return;
1557         }
1558
1559         /* Re-write the session's route group list so that the new order is preserved */
1560
1561         list<RouteGroup*> new_list;
1562
1563         Gtk::TreeModel::Children children = group_model->children();
1564         for (Gtk::TreeModel::Children::iterator i = children.begin(); i != children.end(); ++i) {
1565                 RouteGroup* g = (*i)[group_columns.group];
1566                 if (g) {
1567                         new_list.push_back (g);
1568                 }
1569         }
1570
1571         _session->reorder_route_groups (new_list);
1572 }
1573
1574
1575 void
1576 Mixer_UI::add_route_group (RouteGroup* group)
1577 {
1578         ENSURE_GUI_THREAD (*this, &Mixer_UI::add_route_group, group)
1579         bool focus = false;
1580
1581         in_group_row_change = true;
1582
1583         TreeModel::Row row = *(group_model->append());
1584         row[group_columns.visible] = !group->is_hidden ();
1585         row[group_columns.group] = group;
1586         if (!group->name().empty()) {
1587                 row[group_columns.text] = group->name();
1588         } else {
1589                 row[group_columns.text] = _("unnamed");
1590                 focus = true;
1591         }
1592
1593         group->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::route_group_property_changed, this, group, _1), gui_context());
1594
1595         if (focus) {
1596                 TreeViewColumn* col = group_display.get_column (0);
1597                 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
1598                 group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true);
1599         }
1600
1601         _group_tabs->set_dirty ();
1602
1603         in_group_row_change = false;
1604 }
1605
1606 bool
1607 Mixer_UI::strip_scroller_button_release (GdkEventButton* ev)
1608 {
1609         using namespace Menu_Helpers;
1610
1611         if (Keyboard::is_context_menu_event (ev)) {
1612                 // ARDOUR_UI::instance()->add_route (this);
1613                 return true;
1614         }
1615
1616         return false;
1617 }
1618
1619 void
1620 Mixer_UI::set_strip_width (Width w, bool save)
1621 {
1622         _strip_width = w;
1623
1624         for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1625                 (*i)->set_width_enum (w, save ? (*i)->width_owner() : this);
1626         }
1627 }
1628
1629
1630 struct PluginStateSorter {
1631 public:
1632         bool operator() (PluginInfoPtr a, PluginInfoPtr b) const {
1633                 std::list<std::string>::const_iterator aiter = std::find(_user.begin(), _user.end(), (*a).unique_id);
1634                 std::list<std::string>::const_iterator biter = std::find(_user.begin(), _user.end(), (*b).unique_id);
1635                 if (aiter != _user.end() && biter != _user.end()) {
1636                         return std::distance (_user.begin(), aiter)  < std::distance (_user.begin(), biter);
1637                 }
1638                 if (aiter != _user.end()) {
1639                         return true;
1640                 }
1641                 if (biter != _user.end()) {
1642                         return false;
1643                 }
1644                 return ARDOUR::cmp_nocase((*a).name, (*b).name) == -1;
1645         }
1646
1647         PluginStateSorter(std::list<std::string> user) : _user (user)  {}
1648 private:
1649         std::list<std::string> _user;
1650 };
1651
1652 int
1653 Mixer_UI::set_state (const XMLNode& node, int version)
1654 {
1655         const XMLProperty* prop;
1656
1657         Tabbable::set_state (node, version);
1658
1659         if ((prop = node.property ("narrow-strips"))) {
1660                 if (string_is_affirmative (prop->value())) {
1661                         set_strip_width (Narrow);
1662                 } else {
1663                         set_strip_width (Wide);
1664                 }
1665         }
1666
1667         if ((prop = node.property ("show-mixer"))) {
1668                 if (string_is_affirmative (prop->value())) {
1669                        _visible = true;
1670                 }
1671         }
1672
1673         if ((prop = node.property ("maximised"))) {
1674                 bool yn = string_is_affirmative (prop->value());
1675                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalMixer"));
1676                 assert (act);
1677                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1678                 bool fs = tact && tact->get_active();
1679                 if (yn ^ fs) {
1680                         ActionManager::do_action ("Common", "ToggleMaximalMixer");
1681                 }
1682         }
1683
1684         if ((prop = node.property ("show-mixer-list"))) {
1685                 bool yn = string_is_affirmative (prop->value());
1686                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMixerList"));
1687                 assert (act);
1688                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1689
1690                 /* do it twice to force the change */
1691                 tact->set_active (!yn);
1692                 tact->set_active (yn);
1693         }
1694
1695
1696         XMLNode* plugin_order;
1697         if ((plugin_order = find_named_node (node, "PluginOrder")) != 0) {
1698                 store_current_favorite_order ();
1699                 std::list<string> order;
1700                 const XMLNodeList& kids = plugin_order->children("PluginInfo");
1701                 XMLNodeConstIterator i;
1702                 for (i = kids.begin(); i != kids.end(); ++i) {
1703                         if ((prop = (*i)->property ("unique-id"))) {
1704                                 std::string unique_id = prop->value();
1705                                 order.push_back (unique_id);
1706                                 if ((prop = (*i)->property ("expanded"))) {
1707                                         favorite_ui_state[unique_id] = string_is_affirmative (prop->value());
1708                                 }
1709                         }
1710                 }
1711                 PluginStateSorter cmp (order);
1712                 favorite_order.sort (cmp);
1713                 sync_treeview_from_favorite_order ();
1714         }
1715         return 0;
1716 }
1717
1718 XMLNode&
1719 Mixer_UI::get_state ()
1720 {
1721         XMLNode* node = new XMLNode (X_("Mixer"));
1722         char buf[128];
1723
1724         node->add_child_nocopy (Tabbable::get_state());
1725
1726         snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (const_cast<GtkPaned*>(static_cast<const Paned*>(&rhs_pane1)->gobj())));
1727         node->add_property(X_("mixer_rhs_pane1_pos"), string(buf));
1728         snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (const_cast<GtkPaned*>(static_cast<const Paned*>(&list_hpane)->gobj())));
1729         node->add_property(X_("mixer_list_hpane_pos"), string(buf));
1730
1731         node->add_property ("narrow-strips", _strip_width == Narrow ? "yes" : "no");
1732         node->add_property ("show-mixer", _visible ? "yes" : "no");
1733         node->add_property ("show-mixer-list", _show_mixer_list ? "yes" : "no");
1734         node->add_property ("maximised", _maximised ? "yes" : "no");
1735
1736         return *node;
1737 }
1738
1739 void
1740 Mixer_UI::pane_allocation_handler (Allocation&, Gtk::Paned* which)
1741 {
1742         int pos;
1743         XMLProperty* prop = 0;
1744         XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
1745         XMLNode* geometry;
1746         int height;
1747         static int32_t done[3] = { 0, 0, 0 };
1748
1749         height = default_height;
1750
1751         if ((geometry = find_named_node (*node, "geometry")) != 0) {
1752
1753                 if ((prop = geometry->property ("y_size")) == 0) {
1754                         prop = geometry->property ("y-size");
1755                 }
1756                 if (prop) {
1757                         height = atoi (prop->value());
1758                 }
1759         }
1760
1761         if (which == static_cast<Gtk::Paned*> (&rhs_pane1)) {
1762
1763                 if (done[0]) {
1764                         return;
1765                 }
1766
1767                 if (!geometry || (prop = geometry->property("mixer-rhs-pane1-pos")) == 0) {
1768                         pos = height / 3;
1769                 } else {
1770                         pos = atoi (prop->value());
1771                 }
1772
1773                 if ((done[0] = GTK_WIDGET(rhs_pane1.gobj())->allocation.height > pos)) {
1774                         rhs_pane1.set_position (pos);
1775                 }
1776
1777         } else if (which == static_cast<Gtk::Paned*> (&rhs_pane2)) {
1778                 if (done[1]) {
1779                         return;
1780                 }
1781
1782                 if (!geometry || (prop = geometry->property("mixer-rhs-pane2-pos")) == 0) {
1783                         pos = 2 * height / 3;
1784                 } else {
1785                         pos = atoi (prop->value());
1786                 }
1787
1788                 if ((done[1] = GTK_WIDGET(rhs_pane2.gobj())->allocation.height > pos)) {
1789                         rhs_pane2.set_position (pos);
1790                 }
1791         } else if (which == static_cast<Gtk::Paned*> (&list_hpane)) {
1792
1793                 if (done[2]) {
1794                         return;
1795                 }
1796
1797                 if (!geometry || (prop = geometry->property("mixer-list-hpane-pos")) == 0) {
1798                         pos = std::max ((float)100, rintf ((float) 125 * UIConfiguration::instance().get_ui_scale()));
1799                 } else {
1800                         pos = max (36, atoi (prop->value ()));
1801                 }
1802
1803                 if ((done[2] = GTK_WIDGET(list_hpane.gobj())->allocation.width > pos)) {
1804                         list_hpane.set_position (pos);
1805                 }
1806         }
1807 }
1808 void
1809 Mixer_UI::scroll_left ()
1810 {
1811         if (!scroller.get_hscrollbar()) return;
1812         Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1813         /* stupid GTK: can't rely on clamping across versions */
1814         scroller.get_hscrollbar()->set_value (max (adj->get_lower(), adj->get_value() - adj->get_step_increment()));
1815 }
1816
1817 void
1818 Mixer_UI::scroll_right ()
1819 {
1820         if (!scroller.get_hscrollbar()) return;
1821         Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1822         /* stupid GTK: can't rely on clamping across versions */
1823         scroller.get_hscrollbar()->set_value (min (adj->get_upper(), adj->get_value() + adj->get_step_increment()));
1824 }
1825
1826 bool
1827 Mixer_UI::on_scroll_event (GdkEventScroll* ev)
1828 {
1829         switch (ev->direction) {
1830         case GDK_SCROLL_LEFT:
1831                 scroll_left ();
1832                 return true;
1833         case GDK_SCROLL_UP:
1834                 if (ev->state & Keyboard::TertiaryModifier) {
1835                         scroll_left ();
1836                         return true;
1837                 }
1838                 return false;
1839
1840         case GDK_SCROLL_RIGHT:
1841                 scroll_right ();
1842                 return true;
1843
1844         case GDK_SCROLL_DOWN:
1845                 if (ev->state & Keyboard::TertiaryModifier) {
1846                         scroll_right ();
1847                         return true;
1848                 }
1849                 return false;
1850         }
1851
1852         return false;
1853 }
1854
1855
1856 void
1857 Mixer_UI::parameter_changed (string const & p)
1858 {
1859         if (p == "show-group-tabs") {
1860                 bool const s = _session->config.get_show_group_tabs ();
1861                 if (s) {
1862                         _group_tabs->show ();
1863                 } else {
1864                         _group_tabs->hide ();
1865                 }
1866         } else if (p == "default-narrow_ms") {
1867                 bool const s = UIConfiguration::instance().get_default_narrow_ms ();
1868                 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1869                         (*i)->set_width_enum (s ? Narrow : Wide, this);
1870                 }
1871         } else if (p == "remote-model") {
1872                 reset_remote_control_ids ();
1873         } else if (p == "use-monitor-bus") {
1874                 if (_session && !_session->monitor_out()) {
1875                         monitor_section_detached ();
1876                 }
1877         }
1878 }
1879
1880 void
1881 Mixer_UI::set_route_group_activation (RouteGroup* g, bool a)
1882 {
1883         g->set_active (a, this);
1884 }
1885
1886 PluginSelector*
1887 Mixer_UI::plugin_selector()
1888 {
1889 #ifdef DEFER_PLUGIN_SELECTOR_LOAD
1890         if (!_plugin_selector)
1891                 _plugin_selector = new PluginSelector (PluginManager::instance());
1892 #endif
1893
1894         return _plugin_selector;
1895 }
1896
1897 void
1898 Mixer_UI::setup_track_display ()
1899 {
1900         track_model = ListStore::create (track_columns);
1901         track_display.set_model (track_model);
1902         track_display.append_column (_("Strips"), track_columns.text);
1903         track_display.append_column (_("Show"), track_columns.visible);
1904         track_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
1905         track_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
1906         track_display.get_column (0)->set_expand(true);
1907         track_display.get_column (1)->set_expand(false);
1908         track_display.get_column (0)->set_sizing (Gtk::TREE_VIEW_COLUMN_FIXED);
1909         track_display.set_name (X_("EditGroupList"));
1910         track_display.get_selection()->set_mode (Gtk::SELECTION_NONE);
1911         track_display.set_reorderable (true);
1912         track_display.set_headers_visible (true);
1913         track_display.set_can_focus(false);
1914
1915         track_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_delete));
1916         track_model->signal_rows_reordered().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_reorder));
1917
1918         CellRendererToggle* track_list_visible_cell = dynamic_cast<CellRendererToggle*>(track_display.get_column_cell_renderer (1));
1919         track_list_visible_cell->property_activatable() = true;
1920         track_list_visible_cell->property_radio() = false;
1921         track_list_visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &Mixer_UI::track_visibility_changed));
1922
1923         track_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::track_display_button_press), false);
1924
1925         track_display_scroller.add (track_display);
1926         track_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1927
1928         VBox* v = manage (new VBox);
1929         v->show ();
1930         v->pack_start (track_display_scroller, true, true);
1931
1932         Button* b = manage (new Button);
1933         b->show ();
1934         Widget* w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
1935         w->show ();
1936         b->add (*w);
1937
1938         b->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus));
1939
1940         v->pack_start (*b, false, false);
1941
1942         track_display_frame.set_name("BaseFrame");
1943         track_display_frame.set_shadow_type (Gtk::SHADOW_IN);
1944         track_display_frame.add (*v);
1945
1946         track_display_scroller.show();
1947         track_display_frame.show();
1948         track_display.show();
1949 }
1950
1951 void
1952 Mixer_UI::new_track_or_bus ()
1953 {
1954         // ARDOUR_UI::instance()->add_route (this);
1955 }
1956
1957
1958 void
1959 Mixer_UI::update_title ()
1960 {
1961         if (!own_window()) {
1962                 return;
1963         }
1964
1965         if (_session) {
1966                 string n;
1967
1968                 if (_session->snap_name() != _session->name()) {
1969                         n = _session->snap_name ();
1970                 } else {
1971                         n = _session->name ();
1972                 }
1973
1974                 if (_session->dirty ()) {
1975                         n = "*" + n;
1976                 }
1977
1978                 WindowTitle title (n);
1979                 title += S_("Window|Mixer");
1980                 title += Glib::get_application_name ();
1981                 own_window()->set_title (title.get_string());
1982
1983         } else {
1984
1985                 WindowTitle title (S_("Window|Mixer"));
1986                 title += Glib::get_application_name ();
1987                 own_window()->set_title (title.get_string());
1988         }
1989 }
1990
1991 MixerStrip*
1992 Mixer_UI::strip_by_x (int x)
1993 {
1994         for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1995                 int x1, x2, y;
1996
1997                 (*i)->translate_coordinates (_content, 0, 0, x1, y);
1998                 x2 = x1 + (*i)->get_width();
1999
2000                 if (x >= x1 && x <= x2) {
2001                         return (*i);
2002                 }
2003         }
2004
2005         return 0;
2006 }
2007
2008 void
2009 Mixer_UI::set_route_targets_for_operation ()
2010 {
2011         _route_targets.clear ();
2012
2013         if (!_selection.empty()) {
2014                 _route_targets = _selection.routes;
2015                 return;
2016         }
2017
2018 //  removed "implicit" selections of strips, after discussion on IRC
2019
2020 }
2021
2022 void
2023 Mixer_UI::monitor_section_going_away ()
2024 {
2025         if (_monitor_section) {
2026                 monitor_section_detached ();
2027                 out_packer.remove (_monitor_section->tearoff());
2028                 _monitor_section->set_session (0);
2029                 delete _monitor_section;
2030                 _monitor_section = 0;
2031         }
2032 }
2033
2034 void
2035 Mixer_UI::toggle_midi_input_active (bool flip_others)
2036 {
2037         boost::shared_ptr<RouteList> rl (new RouteList);
2038         bool onoff = false;
2039
2040         set_route_targets_for_operation ();
2041
2042         for (RouteUISelection::iterator r = _route_targets.begin(); r != _route_targets.end(); ++r) {
2043                 boost::shared_ptr<MidiTrack> mt = (*r)->midi_track();
2044
2045                 if (mt) {
2046                         rl->push_back ((*r)->route());
2047                         onoff = !mt->input_active();
2048                 }
2049         }
2050
2051         _session->set_exclusive_input_active (rl, onoff, flip_others);
2052 }
2053
2054 void
2055 Mixer_UI::maximise_mixer_space ()
2056 {
2057         if (!own_window()) {
2058                 return;
2059         }
2060
2061         if (_maximised) {
2062                 return;
2063         }
2064
2065         _window->fullscreen ();
2066         _maximised = true;
2067 }
2068
2069 void
2070 Mixer_UI::restore_mixer_space ()
2071 {
2072         if (!own_window()) {
2073                 return;
2074         }
2075
2076         if (!_maximised) {
2077                 return;
2078         }
2079
2080         own_window()->unfullscreen();
2081         _maximised = false;
2082 }
2083
2084 void
2085 Mixer_UI::monitor_section_attached ()
2086 {
2087         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
2088         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2089         act->set_sensitive (true);
2090         tact->set_active ();
2091 }
2092
2093 void
2094 Mixer_UI::monitor_section_detached ()
2095 {
2096         Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
2097         act->set_sensitive (false);
2098 }
2099
2100 void
2101 Mixer_UI::store_current_favorite_order ()
2102 {
2103         typedef Gtk::TreeModel::Children type_children;
2104         type_children children = favorite_plugins_model->children();
2105         favorite_order.clear();
2106         for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter)
2107         {
2108                 Gtk::TreeModel::Row row = *iter;
2109                 ARDOUR::PluginPresetPtr ppp = row[favorite_plugins_columns.plugin];
2110                 favorite_order.push_back (ppp->_pip);
2111                 std::string name = row[favorite_plugins_columns.name];
2112                 favorite_ui_state[(*ppp->_pip).unique_id] = favorite_plugins_display.row_expanded (favorite_plugins_model->get_path(iter));
2113         }
2114 }
2115
2116 void
2117 Mixer_UI::save_favorite_ui_state (const TreeModel::iterator& iter, const TreeModel::Path& path)
2118 {
2119         Gtk::TreeModel::Row row = *iter;
2120         ARDOUR::PluginPresetPtr ppp = row[favorite_plugins_columns.plugin];
2121         assert (ppp);
2122         favorite_ui_state[(*ppp->_pip).unique_id] = favorite_plugins_display.row_expanded (favorite_plugins_model->get_path(iter));
2123 }
2124
2125 void
2126 Mixer_UI::refiller (PluginInfoList& result, const PluginInfoList& plugs)
2127 {
2128         PluginManager& manager (PluginManager::instance());
2129         for (PluginInfoList::const_iterator i = plugs.begin(); i != plugs.end(); ++i) {
2130                 if (manager.get_status (*i) != PluginManager::Favorite) {
2131                         continue;
2132                 }
2133                 result.push_back (*i);
2134         }
2135 }
2136
2137 struct PluginCustomSorter {
2138 public:
2139         bool operator() (PluginInfoPtr a, PluginInfoPtr b) const {
2140                 PluginInfoList::const_iterator aiter = _user.begin();
2141                 PluginInfoList::const_iterator biter = _user.begin();
2142                 while (aiter != _user.end()) { if ((*aiter)->unique_id == a->unique_id) { break; } ++aiter; }
2143                 while (biter != _user.end()) { if ((*biter)->unique_id == b->unique_id) { break; } ++biter; }
2144
2145                 if (aiter != _user.end() && biter != _user.end()) {
2146                         return std::distance (_user.begin(), aiter) < std::distance (_user.begin(), biter);
2147                 }
2148                 if (aiter != _user.end()) {
2149                         return true;
2150                 }
2151                 if (biter != _user.end()) {
2152                         return false;
2153                 }
2154                 return ARDOUR::cmp_nocase((*a).name, (*b).name) == -1;
2155         }
2156         PluginCustomSorter(PluginInfoList user) : _user (user)  {}
2157 private:
2158         PluginInfoList _user;
2159 };
2160
2161 void
2162 Mixer_UI::refill_favorite_plugins ()
2163 {
2164         PluginInfoList plugs;
2165         PluginManager& mgr (PluginManager::instance());
2166
2167 #ifdef LV2_SUPPORT
2168         refiller (plugs, mgr.lv2_plugin_info ());
2169 #endif
2170 #ifdef WINDOWS_VST_SUPPORT
2171         refiller (plugs, mgr.windows_vst_plugin_info ());
2172 #endif
2173 #ifdef LXVST_SUPPORT
2174         refiller (plugs, mgr.lxvst_plugin_info ());
2175 #endif
2176 #ifdef AUDIOUNIT_SUPPORT
2177         refiller (plugs, mgr.au_plugin_info ());
2178 #endif
2179         refiller (plugs, mgr.ladspa_plugin_info ());
2180
2181         store_current_favorite_order ();
2182
2183         PluginCustomSorter cmp (favorite_order);
2184         plugs.sort (cmp);
2185
2186         favorite_order = plugs;
2187
2188         sync_treeview_from_favorite_order ();
2189 }
2190
2191 void
2192 Mixer_UI::sync_treeview_favorite_ui_state (const TreeModel::Path& path, const TreeModel::iterator&)
2193 {
2194         TreeIter iter;
2195         if (!(iter = favorite_plugins_model->get_iter (path))) {
2196                 return;
2197         }
2198         ARDOUR::PluginPresetPtr ppp = (*iter)[favorite_plugins_columns.plugin];
2199         if (!ppp) {
2200                 return;
2201         }
2202         PluginInfoPtr pip = ppp->_pip;
2203         if (favorite_ui_state.find (pip->unique_id) != favorite_ui_state.end ()) {
2204                 if (favorite_ui_state[pip->unique_id]) {
2205                         favorite_plugins_display.expand_row (path, true);
2206                 }
2207         }
2208 }
2209
2210 void
2211 Mixer_UI::sync_treeview_from_favorite_order ()
2212 {
2213         favorite_plugins_model->clear ();
2214         for (PluginInfoList::const_iterator i = favorite_order.begin(); i != favorite_order.end(); ++i) {
2215                 PluginInfoPtr pip = (*i);
2216
2217                 TreeModel::Row newrow = *(favorite_plugins_model->append());
2218                 newrow[favorite_plugins_columns.name] = (*i)->name;
2219                 newrow[favorite_plugins_columns.plugin] = PluginPresetPtr (new PluginPreset(pip));
2220                 if (!_session) {
2221                         continue;
2222                 }
2223
2224                 vector<ARDOUR::Plugin::PresetRecord> presets = (*i)->get_presets (true);
2225                 for (vector<ARDOUR::Plugin::PresetRecord>::const_iterator j = presets.begin(); j != presets.end(); ++j) {
2226                         Gtk::TreeModel::Row child_row = *(favorite_plugins_model->append (newrow.children()));
2227                         child_row[favorite_plugins_columns.name] = (*j).label;
2228                         child_row[favorite_plugins_columns.plugin] = PluginPresetPtr (new PluginPreset(pip, &(*j)));
2229                 }
2230                 if (favorite_ui_state.find (pip->unique_id) != favorite_ui_state.end ()) {
2231                         if (favorite_ui_state[pip->unique_id]) {
2232                                 favorite_plugins_display.expand_row (favorite_plugins_model->get_path(newrow), true);
2233                         }
2234                 }
2235         }
2236 }
2237
2238 void
2239 Mixer_UI::popup_note_context_menu (GdkEventButton *ev)
2240 {
2241         using namespace Gtk::Menu_Helpers;
2242
2243         Gtk::Menu* m = manage (new Menu);
2244         MenuList& items = m->items ();
2245
2246         if (_selection.routes.empty()) {
2247                 items.push_back (MenuElem (_("No Track/Bus is selected.")));
2248         } else {
2249                 items.push_back (MenuElem (_("Add at the top"),
2250                                         sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddTop)));
2251                 items.push_back (MenuElem (_("Add Pre-Fader"),
2252                                         sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddPreFader)));
2253                 items.push_back (MenuElem (_("Add Post-Fader"),
2254                                         sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddPostFader)));
2255                 items.push_back (MenuElem (_("Add at the end"),
2256                                         sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddBottom)));
2257         }
2258
2259         items.push_back (SeparatorElem());
2260
2261         items.push_back (MenuElem (_("Remove from favorites"), sigc::mem_fun (*this, &Mixer_UI::remove_selected_from_favorites)));
2262
2263         ARDOUR::PluginPresetPtr ppp = selected_plugin();
2264         if (ppp && ppp->_preset.valid && ppp->_preset.user) {
2265                 // we cannot currently delete AU presets
2266                 if (!ppp->_pip || ppp->_pip->type != AudioUnit) {
2267                         items.push_back (MenuElem (_("Delete Preset"), sigc::mem_fun (*this, &Mixer_UI::delete_selected_preset)));
2268                 }
2269         }
2270
2271         m->popup (ev->button, ev->time);
2272 }
2273
2274 bool
2275 Mixer_UI::plugin_row_button_press (GdkEventButton *ev)
2276 {
2277         if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 3) ) {
2278                 TreeModel::Path path;
2279                 TreeViewColumn* column;
2280                 int cellx, celly;
2281                 if (favorite_plugins_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
2282                         Glib::RefPtr<Gtk::TreeView::Selection> selection = favorite_plugins_display.get_selection();
2283                         if (selection) {
2284                                 selection->unselect_all();
2285                                 selection->select(path);
2286                         }
2287                 }
2288                 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2289                 if (ppp) {
2290                         popup_note_context_menu (ev);
2291                 }
2292         }
2293         return false;
2294 }
2295
2296
2297 PluginPresetPtr
2298 Mixer_UI::selected_plugin ()
2299 {
2300         Glib::RefPtr<Gtk::TreeView::Selection> selection = favorite_plugins_display.get_selection();
2301         if (!selection) {
2302                 return PluginPresetPtr();
2303         }
2304         Gtk::TreeModel::iterator iter = selection->get_selected();
2305         if (!iter) {
2306                 return PluginPresetPtr();
2307         }
2308         return (*iter)[favorite_plugins_columns.plugin];
2309 }
2310
2311 void
2312 Mixer_UI::add_selected_processor (ProcessorPosition pos)
2313 {
2314         ARDOUR::PluginPresetPtr ppp = selected_plugin();
2315         if (ppp) {
2316                 add_favorite_processor (ppp, pos);
2317         }
2318 }
2319
2320 void
2321 Mixer_UI::delete_selected_preset ()
2322 {
2323         if (!_session) {
2324                 return;
2325         }
2326         ARDOUR::PluginPresetPtr ppp = selected_plugin();
2327         if (!ppp || !ppp->_preset.valid || !ppp->_preset.user) {
2328                 return;
2329         }
2330         PluginPtr plugin = ppp->_pip->load (*_session);
2331         plugin->get_presets();
2332         plugin->remove_preset (ppp->_preset.label);
2333 }
2334
2335 void
2336 Mixer_UI::remove_selected_from_favorites ()
2337 {
2338         ARDOUR::PluginPresetPtr ppp = selected_plugin();
2339         if (!ppp) {
2340                 return;
2341         }
2342         PluginManager::PluginStatusType status = PluginManager::Normal;
2343         PluginManager& manager (PluginManager::instance());
2344
2345         manager.set_status (ppp->_pip->type, ppp->_pip->unique_id, status);
2346         manager.save_statuses ();
2347 }
2348
2349 void
2350 Mixer_UI::plugin_row_activated (const TreeModel::Path& path, TreeViewColumn* column)
2351 {
2352         TreeIter iter;
2353         if (!(iter = favorite_plugins_model->get_iter (path))) {
2354                 return;
2355         }
2356         ARDOUR::PluginPresetPtr ppp = (*iter)[favorite_plugins_columns.plugin];
2357         add_favorite_processor (ppp, AddPreFader); // TODO: preference?!
2358 }
2359
2360 void
2361 Mixer_UI::add_favorite_processor (ARDOUR::PluginPresetPtr ppp, ProcessorPosition pos)
2362 {
2363         if (!_session || _selection.routes.empty()) {
2364                 return;
2365         }
2366
2367         PluginInfoPtr pip = ppp->_pip;
2368         for (RouteUISelection::iterator i = _selection.routes.begin(); i != _selection.routes.end(); ++i) {
2369                 boost::shared_ptr<ARDOUR::Route> rt = (*i)->route();
2370                 if (!rt) { continue; }
2371
2372                 PluginPtr p = pip->load (*_session);
2373                 if (!p) { continue; }
2374
2375                 if (ppp->_preset.valid) {
2376                         p->load_preset (ppp->_preset);
2377                 }
2378
2379                 Route::ProcessorStreams err;
2380                 boost::shared_ptr<Processor> processor (new PluginInsert (*_session, p));
2381
2382                 switch (pos) {
2383                         case AddTop:
2384                                 rt->add_processor_by_index (processor, 0, &err, Config->get_new_plugins_active ());
2385                                 break;
2386                         case AddPreFader:
2387                                 rt->add_processor (processor, PreFader, &err, Config->get_new_plugins_active ());
2388                                 break;
2389                         case AddPostFader:
2390                                 {
2391                                         int idx = 0;
2392                                         for (;;++idx) {
2393                                                 boost::shared_ptr<Processor> np = rt->nth_processor (idx);
2394                                                 if (!np || boost::dynamic_pointer_cast<Amp> (np)) {
2395                                                         break;
2396                                                 }
2397                                         }
2398                                         rt->add_processor_by_index (processor, ++idx, &err, Config->get_new_plugins_active ());
2399                                 }
2400                                 break;
2401                         case AddBottom:
2402                                 rt->add_processor_by_index (processor, -1, &err, Config->get_new_plugins_active ());
2403                                 break;
2404                 }
2405         }
2406 }
2407
2408 bool
2409 PluginTreeStore::row_drop_possible_vfunc(const Gtk::TreeModel::Path& dest, const Gtk::SelectionData& data) const
2410 {
2411         if (data.get_target() != "GTK_TREE_MODEL_ROW") {
2412                 return false;
2413         }
2414
2415         // only allow to re-order top-level items
2416         TreePath src;
2417         if (TreePath::get_from_selection_data (data, src)) {
2418                 if (src.up() && src.up()) {
2419                         return false;
2420                 }
2421         }
2422
2423         // don't allow to drop as child-rows.
2424         Gtk::TreeModel::Path _dest = dest; // un const
2425         const bool is_child = _dest.up (); // explicit bool for clang
2426         if (!is_child || _dest.empty ()) {
2427                 return true;
2428         }
2429         return false;
2430 }
2431
2432 void
2433 Mixer_UI::plugin_drop (const Glib::RefPtr<Gdk::DragContext>&, const Gtk::SelectionData& data)
2434 {
2435         if (data.get_target() != "PluginPresetPtr") {
2436                 return;
2437         }
2438         if (data.get_length() != sizeof (PluginPresetPtr)) {
2439                 return;
2440         }
2441         const void *d = data.get_data();
2442         const PluginPresetPtr ppp = *(static_cast<const PluginPresetPtr*> (d));
2443
2444         PluginManager::PluginStatusType status = PluginManager::Favorite;
2445         PluginManager& manager (PluginManager::instance());
2446
2447         manager.set_status (ppp->_pip->type, ppp->_pip->unique_id, status);
2448         manager.save_statuses ();
2449 }