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