merge from 2.0-ongoing @ 3581
[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 #include <algorithm>
21 #include <sigc++/bind.h>
22
23 #include <gtkmm/accelmap.h>
24
25 #include <pbd/convert.h>
26 #include <glibmm/thread.h>
27
28 #include <gtkmm2ext/gtk_ui.h>
29 #include <gtkmm2ext/utils.h>
30 #include <gtkmm2ext/stop_signal.h>
31 #include <gtkmm2ext/window_title.h>
32
33 #include <ardour/session.h>
34 #include <ardour/audio_track.h>
35 #include <ardour/session_route.h>
36 #include <ardour/audio_diskstream.h>
37 #include <ardour/plugin_manager.h>
38
39 #include "keyboard.h"
40 #include "mixer_ui.h"
41 #include "mixer_strip.h"
42 #include "plugin_selector.h"
43 #include "ardour_ui.h"
44 #include "prompter.h"
45 #include "utils.h"
46 #include "actions.h"
47 #include "gui_thread.h"
48
49 #include "i18n.h"
50
51 using namespace ARDOUR;
52 using namespace PBD;
53 using namespace Gtk;
54 using namespace Glib;
55 using namespace Gtkmm2ext;
56 using namespace sigc;
57 using namespace std;
58
59 using PBD::atoi;
60
61 Mixer_UI::Mixer_UI ()
62         : Window (Gtk::WINDOW_TOPLEVEL)
63 {
64         session = 0;
65         _strip_width = Config->get_default_narrow_ms() ? Narrow : Wide;
66         track_menu = 0;
67         mix_group_context_menu = 0;
68         no_track_list_redisplay = false;
69         in_group_row_change = false;
70         _visible = false;
71         ignore_route_reorder = false;
72         ignore_sync = false;
73
74         Route::SyncOrderKeys.connect (mem_fun (*this, &Mixer_UI::sync_order_keys));
75
76         scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
77         scroller_base.set_name ("MixerWindow");
78         scroller_base.signal_button_release_event().connect (mem_fun(*this, &Mixer_UI::strip_scroller_button_release));
79         // add as last item of strip packer
80         strip_packer.pack_end (scroller_base, true, true);
81
82         scroller.add (strip_packer);
83         scroller.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC);
84
85         track_model = ListStore::create (track_columns);
86         track_display.set_model (track_model);
87         track_display.append_column (_("Strips"), track_columns.text);
88         track_display.append_column (_("Show"), track_columns.visible);
89         track_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
90         track_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
91         track_display.get_column (0)->set_expand(true);
92         track_display.get_column (1)->set_expand(false);
93         track_display.set_name (X_("MixerTrackDisplayList"));
94         track_display.get_selection()->set_mode (Gtk::SELECTION_NONE);
95         track_display.set_reorderable (true);
96         track_display.set_headers_visible (true);
97
98         track_model->signal_row_deleted().connect (mem_fun (*this, &Mixer_UI::track_list_delete));
99         track_model->signal_row_changed().connect (mem_fun (*this, &Mixer_UI::track_list_change));
100         track_model->signal_rows_reordered().connect (mem_fun (*this, &Mixer_UI::track_list_reorder));
101
102         CellRendererToggle* track_list_visible_cell = dynamic_cast<CellRendererToggle*>(track_display.get_column_cell_renderer (1));
103         track_list_visible_cell->property_activatable() = true;
104         track_list_visible_cell->property_radio() = false;
105
106         track_display.signal_button_press_event().connect (mem_fun (*this, &Mixer_UI::track_display_button_press), false);
107
108         track_display_scroller.add (track_display);
109         track_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
110
111         group_model = ListStore::create (group_columns);
112         group_display.set_model (group_model);
113         group_display.append_column (_("Group"), group_columns.text);
114         group_display.append_column (_("Active"), group_columns.active);
115         group_display.append_column (_("Show"), group_columns.visible);
116         group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
117         group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
118         group_display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
119         group_display.get_column (0)->set_expand(true);
120         group_display.get_column (1)->set_expand(false);
121         group_display.get_column (2)->set_expand(false);
122         group_display.set_name ("MixerGroupList");
123         group_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
124         group_display.set_reorderable (true);
125         group_display.set_headers_visible (true);
126         group_display.set_rules_hint (true);
127
128         /* name is directly editable */
129
130         CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
131         name_cell->property_editable() = true;
132         name_cell->signal_edited().connect (mem_fun (*this, &Mixer_UI::mix_group_name_edit));
133
134         /* use checkbox for the active column */
135
136         CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(group_display.get_column_cell_renderer (1));
137         active_cell->property_activatable() = true;
138         active_cell->property_radio() = false;
139
140         /* use checkbox for the visible column */
141
142         active_cell = dynamic_cast<CellRendererToggle*>(group_display.get_column_cell_renderer (2));
143         active_cell->property_activatable() = true;
144         active_cell->property_radio() = false;
145
146         group_model->signal_row_changed().connect (mem_fun (*this, &Mixer_UI::mix_group_row_change));
147
148         group_display.signal_button_press_event().connect (mem_fun (*this, &Mixer_UI::group_display_button_press), false);
149
150         group_display_scroller.add (group_display);
151         group_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
152
153         HBox* mix_group_display_button_box = manage (new HBox());
154
155         Button* mix_group_add_button = manage (new Button ());
156         Button* mix_group_remove_button = manage (new Button ());
157
158         Widget* w;
159
160         w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
161         w->show();
162         mix_group_add_button->add (*w);
163
164         w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
165         w->show();
166         mix_group_remove_button->add (*w);
167
168         mix_group_display_button_box->set_homogeneous (true);
169
170         mix_group_add_button->signal_clicked().connect (mem_fun (*this, &Mixer_UI::new_mix_group));
171         mix_group_remove_button->signal_clicked().connect (mem_fun (*this, &Mixer_UI::remove_selected_mix_group));
172
173         mix_group_display_button_box->add (*mix_group_remove_button);
174         mix_group_display_button_box->add (*mix_group_add_button);
175
176         group_display_vbox.pack_start (group_display_scroller, true, true);
177         group_display_vbox.pack_start (*mix_group_display_button_box, false, false);
178
179         track_display_frame.set_name("BaseFrame");
180         track_display_frame.set_shadow_type (Gtk::SHADOW_IN);
181         track_display_frame.add(track_display_scroller);
182
183         group_display_frame.set_name ("BaseFrame");
184         group_display_frame.set_shadow_type (Gtk::SHADOW_IN);
185         group_display_frame.add (group_display_vbox);
186
187         rhs_pane1.pack1 (track_display_frame);
188         rhs_pane1.pack2 (group_display_frame);
189
190         list_vpacker.pack_start (rhs_pane1, true, true);
191
192         global_hpacker.pack_start (scroller, true, true);
193         global_hpacker.pack_start (out_packer, false, false, 12);
194
195         list_hpane.add1(list_vpacker);
196         list_hpane.add2(global_hpacker);
197
198         rhs_pane1.signal_size_allocate().connect (bind (mem_fun(*this, &Mixer_UI::pane_allocation_handler), 
199                                                         static_cast<Gtk::Paned*> (&rhs_pane1)));
200         list_hpane.signal_size_allocate().connect (bind (mem_fun(*this, &Mixer_UI::pane_allocation_handler), 
201                                                          static_cast<Gtk::Paned*> (&list_hpane)));
202         
203         global_vpacker.pack_start (list_hpane, true, true);
204
205         add (global_vpacker);
206         set_name ("MixerWindow");
207         
208         WindowTitle title(Glib::get_application_name());
209         title += _("Mixer");
210         set_title (title.get_string());
211
212         set_wmclass (X_("ardour_mixer"), "Ardour");
213
214         add_accel_group (ActionManager::ui_manager->get_accel_group());
215
216         signal_delete_event().connect (mem_fun (*this, &Mixer_UI::hide_window));
217         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
218
219         _plugin_selector = new PluginSelector (PluginManager::the_manager());
220
221         signal_configure_event().connect (mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
222
223         _selection.RoutesChanged.connect (mem_fun(*this, &Mixer_UI::follow_strip_selection));
224
225         mix_group_display_button_box->show();
226         mix_group_add_button->show();
227         mix_group_remove_button->show();
228
229         global_hpacker.show();
230         global_vpacker.show();
231         scroller.show();
232         scroller_base.show();
233         scroller_hpacker.show();
234         mixer_scroller_vpacker.show();
235         list_vpacker.show();
236         group_display_button_label.show();
237         group_display_button.show();
238         track_display_scroller.show();
239         group_display_scroller.show();
240         group_display_vbox.show();
241         track_display_frame.show();
242         group_display_frame.show();
243         rhs_pane1.show();
244         strip_packer.show();
245         out_packer.show();
246         list_hpane.show();
247         track_display.show();
248         group_display.show();
249
250         auto_rebinding = FALSE;
251 }
252
253 Mixer_UI::~Mixer_UI ()
254 {
255 }
256
257 void
258 Mixer_UI::ensure_float (Window& win)
259 {
260         win.set_transient_for (*this);
261 }
262
263 void
264 Mixer_UI::show_window ()
265 {
266         present ();
267
268         set_window_pos_and_size ();
269
270         /* now reset each strips width so the right widgets are shown */
271         MixerStrip* ms;
272
273         TreeModel::Children rows = track_model->children();
274         TreeModel::Children::iterator ri;
275
276         for (ri = rows.begin(); ri != rows.end(); ++ri) {
277                 ms = (*ri)[track_columns.strip];
278                 ms->set_width (ms->get_width(), ms->width_owner());
279         }
280         _visible = true;
281 }
282
283 bool
284 Mixer_UI::hide_window (GdkEventAny *ev)
285 {
286         get_window_pos_and_size ();
287
288         _visible = false;
289         return just_hide_it(ev, static_cast<Gtk::Window *>(this));
290 }
291
292
293 void
294 Mixer_UI::add_strip (Session::RouteList& routes)
295 {
296         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::add_strip), routes));
297         
298         MixerStrip* strip;
299
300         for (Session::RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
301                 boost::shared_ptr<Route> route = (*x);
302
303                 if (route->is_hidden()) {
304                         return;
305                 }
306                 
307                 strip = new MixerStrip (*this, *session, route);
308                 strips.push_back (strip);
309                 
310                 Config->get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide;
311
312                 Config->get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide;
313
314                 if (strip->width_owner() != strip) {
315                         strip->set_width (_strip_width, this);
316                 }
317
318                 show_strip (strip);
319                 
320                 no_track_list_redisplay = true;
321                 
322                 TreeModel::Row row = *(track_model->append());
323                 row[track_columns.text] = route->name();
324                 
325                 row[track_columns.visible] = strip->marked_for_display();
326                 row[track_columns.route] = route;
327                 row[track_columns.strip] = strip;
328                 
329                 strip->set_old_order_key (track_model->children().size() - 1);
330
331                 no_track_list_redisplay = false;
332                 redisplay_track_list ();
333                 
334                 route->NameChanged.connect (bind (mem_fun(*this, &Mixer_UI::strip_name_changed), strip));
335                 strip->GoingAway.connect (bind (mem_fun(*this, &Mixer_UI::remove_strip), strip));
336                 
337                 strip->signal_button_release_event().connect (bind (mem_fun(*this, &Mixer_UI::strip_button_release_event), strip));
338         }
339 }
340
341 void
342 Mixer_UI::remove_strip (MixerStrip* strip)
343 {
344         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::remove_strip), strip));
345
346         TreeModel::Children rows = track_model->children();
347         TreeModel::Children::iterator ri;
348         list<MixerStrip *>::iterator i;
349
350         if ((i = find (strips.begin(), strips.end(), strip)) != strips.end()) {
351                 strips.erase (i);
352         }
353
354         /* Decrement old order keys for strips `above' the one that is being removed */
355         for (ri = rows.begin(); ri != rows.end(); ++ri) {
356                 MixerStrip* s = (*ri)[track_columns.strip];
357                 if (s->old_order_key() > strip->old_order_key()) {
358                         s->set_old_order_key (s->old_order_key() - 1);
359                 }
360         }
361
362         for (ri = rows.begin(); ri != rows.end(); ++ri) {
363                 if ((*ri)[track_columns.strip] == strip) {
364                         track_model->erase (ri);
365                         break;
366                 }
367         }
368 }
369
370 const char*
371 Mixer_UI::get_order_key() 
372 {
373         if (Config->get_sync_all_route_ordering()) {
374                 return X_("editor");
375         } else {
376                 return X_("signal");
377         }
378 }
379
380 void
381 Mixer_UI::sync_order_keys ()
382 {
383         vector<int> neworder;
384         TreeModel::Children rows = track_model->children();
385         TreeModel::Children::iterator ri;
386
387         if (ignore_sync || !session || (session->state_of_the_state() & Session::Loading) || rows.empty()) {
388                 return;
389         }
390
391         for (ri = rows.begin(); ri != rows.end(); ++ri) {
392                 neworder.push_back (0);
393         }
394
395         for (ri = rows.begin(); ri != rows.end(); ++ri) {
396                 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
397                 MixerStrip* strip = (*ri)[track_columns.strip];
398                 neworder[route->order_key (get_order_key())] = strip->old_order_key ();
399         }
400
401         ignore_route_reorder = true;
402         track_model->reorder (neworder);
403         ignore_route_reorder = false;
404 }
405
406 void
407 Mixer_UI::follow_strip_selection ()
408 {
409         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
410                 (*i)->set_selected (_selection.selected ((*i)->route()));
411         }
412 }
413
414 bool
415 Mixer_UI::strip_button_release_event (GdkEventButton *ev, MixerStrip *strip)
416 {
417         if (ev->button == 1) {
418
419                 /* this allows the user to click on the strip to terminate comment
420                    editing. XXX it needs improving so that we don't select the strip
421                    at the same time.
422                 */
423                 
424                 if (_selection.selected (strip->route())) {
425                         _selection.remove (strip->route());
426                 } else {
427                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
428                                 _selection.add (strip->route());
429                         } else {
430                                 _selection.set (strip->route());
431                         }
432                 }
433         }
434
435         return true;
436 }
437
438 void
439 Mixer_UI::connect_to_session (Session* sess)
440 {
441
442         session = sess;
443
444         XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
445         set_state (*node);
446
447         WindowTitle title(session->name());
448         title += _("Mixer");
449         title += Glib::get_application_name();
450
451         set_title (title.get_string());
452
453         initial_track_display ();
454
455         session->GoingAway.connect (mem_fun(*this, &Mixer_UI::disconnect_from_session));
456         session->RouteAdded.connect (mem_fun(*this, &Mixer_UI::add_strip));
457         session->mix_group_added.connect (mem_fun(*this, &Mixer_UI::add_mix_group));
458         session->mix_group_removed.connect (mem_fun(*this, &Mixer_UI::mix_groups_changed));
459
460         mix_groups_changed ();
461         
462         _plugin_selector->set_session (session);
463
464         if (_visible) {
465                show_window();
466         }
467
468         start_updating ();
469 }
470
471 void
472 Mixer_UI::disconnect_from_session ()
473 {
474         ENSURE_GUI_THREAD(mem_fun(*this, &Mixer_UI::disconnect_from_session));
475         
476         group_model->clear ();
477         _selection.clear ();
478
479         WindowTitle title(Glib::get_application_name());
480         title += _("Mixer");
481         set_title (title.get_string());
482         
483         stop_updating ();
484 }
485
486 void
487 Mixer_UI::show_strip (MixerStrip* ms)
488 {
489         TreeModel::Children rows = track_model->children();
490         TreeModel::Children::iterator i;
491         
492         for (i = rows.begin(); i != rows.end(); ++i) {
493         
494                 MixerStrip* strip = (*i)[track_columns.strip];
495                 if (strip == ms) {
496                         (*i)[track_columns.visible] = true;
497                         break;
498                 }
499         }
500 }
501
502 void
503 Mixer_UI::hide_strip (MixerStrip* ms)
504 {
505         TreeModel::Children rows = track_model->children();
506         TreeModel::Children::iterator i;
507         
508         for (i = rows.begin(); i != rows.end(); ++i) {
509                 
510                 MixerStrip* strip = (*i)[track_columns.strip];
511                 if (strip == ms) {
512                         (*i)[track_columns.visible] = false;
513                         break;
514                 }
515         }
516 }
517
518 gint
519 Mixer_UI::start_updating ()
520 {
521     fast_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun(*this, &Mixer_UI::fast_update_strips));
522     return 0;
523 }
524
525 gint
526 Mixer_UI::stop_updating ()
527 {
528     fast_screen_update_connection.disconnect();
529     return 0;
530 }
531
532 void
533 Mixer_UI::fast_update_strips ()
534 {
535         if (is_mapped () && session) {
536                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
537                         (*i)->fast_update ();
538                 }
539         }
540 }
541
542 void
543 Mixer_UI::set_all_strips_visibility (bool yn)
544 {
545         TreeModel::Children rows = track_model->children();
546         TreeModel::Children::iterator i;
547
548         no_track_list_redisplay = true;
549
550         for (i = rows.begin(); i != rows.end(); ++i) {
551
552                 TreeModel::Row row = (*i);
553                 MixerStrip* strip = row[track_columns.strip];
554                 
555                 if (strip == 0) {
556                         continue;
557                 }
558                 
559                 if (strip->route()->is_master() || strip->route()->is_control()) {
560                         continue;
561                 }
562
563                 (*i)[track_columns.visible] = yn;
564         }
565
566         no_track_list_redisplay = false;
567         redisplay_track_list ();
568 }
569
570
571 void
572 Mixer_UI::set_all_audio_visibility (int tracks, bool yn) 
573 {
574         TreeModel::Children rows = track_model->children();
575         TreeModel::Children::iterator i;
576
577         no_track_list_redisplay = true;
578
579         for (i = rows.begin(); i != rows.end(); ++i) {
580                 TreeModel::Row row = (*i);
581                 MixerStrip* strip = row[track_columns.strip];
582
583                 if (strip == 0) {
584                         continue;
585                 }
586
587                 if (strip->route()->is_master() || strip->route()->is_control()) {
588                         continue;
589                 }
590
591                 boost::shared_ptr<AudioTrack> at = strip->audio_track();
592
593                 switch (tracks) {
594                 case 0:
595                         (*i)[track_columns.visible] = yn;
596                         break;
597                         
598                 case 1:
599                         if (at) { /* track */
600                                 (*i)[track_columns.visible] = yn;
601                         }
602                         break;
603                         
604                 case 2:
605                         if (!at) { /* bus */
606                                 (*i)[track_columns.visible] = yn;
607                         }
608                         break;
609                 }
610         }
611
612         no_track_list_redisplay = false;
613         redisplay_track_list ();
614 }
615
616 void
617 Mixer_UI::hide_all_routes ()
618 {
619         set_all_strips_visibility (false);
620 }
621
622 void
623 Mixer_UI::show_all_routes ()
624 {
625         set_all_strips_visibility (true);
626 }
627
628 void
629 Mixer_UI::show_all_audiobus ()
630 {
631         set_all_audio_visibility (2, true);
632 }
633 void
634 Mixer_UI::hide_all_audiobus ()
635 {
636         set_all_audio_visibility (2, false);
637 }
638
639 void
640 Mixer_UI::show_all_audiotracks()
641 {
642         set_all_audio_visibility (1, true);
643 }
644 void
645 Mixer_UI::hide_all_audiotracks ()
646 {
647         set_all_audio_visibility (1, false);
648 }
649
650 void
651 Mixer_UI::track_list_reorder (const TreeModel::Path& path, const TreeModel::iterator& iter, int* new_order)
652 {
653         session->set_remote_control_ids();
654         redisplay_track_list ();
655 }
656
657 void
658 Mixer_UI::track_list_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter)
659 {
660         session->set_remote_control_ids();
661         redisplay_track_list ();
662 }
663
664 void
665 Mixer_UI::track_list_delete (const Gtk::TreeModel::Path& path)
666 {
667         session->set_remote_control_ids();
668         redisplay_track_list ();
669 }
670
671 void
672 Mixer_UI::redisplay_track_list ()
673 {
674         TreeModel::Children rows = track_model->children();
675         TreeModel::Children::iterator i;
676         long order;
677
678         if (no_track_list_redisplay) {
679                 return;
680         }
681
682         for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
683                 MixerStrip* strip = (*i)[track_columns.strip];
684
685                 if (strip == 0) {
686                         /* we're in the middle of changing a row, don't worry */
687                         continue;
688                 }
689
690                 bool visible = (*i)[track_columns.visible];
691
692                 if (visible) {
693                         strip->set_marked_for_display (true);
694                         strip->route()->set_order_key (N_("signal"), order);
695
696                         if (!ignore_route_reorder) {
697                                 strip->route()->set_order_key (get_order_key(), order);
698                         } 
699
700                         if (strip->packed()) {
701
702                                 if (strip->route()->is_master() || strip->route()->is_control()) {
703                                         out_packer.reorder_child (*strip, -1);
704                                 } else {
705                                         strip_packer.reorder_child (*strip, -1); /* put at end */
706                                 }
707
708                         } else {
709
710                                 if (strip->route()->is_master() || strip->route()->is_control()) {
711                                         out_packer.pack_start (*strip, false, false);
712                                 } else {
713                                         strip_packer.pack_start (*strip, false, false);
714                                 }
715                                 strip->set_packed (true);
716                                 //strip->show();
717                         }
718
719                 } else {
720
721                         if (strip->route()->is_master() || strip->route()->is_control()) {
722                                 /* do nothing, these cannot be hidden */
723                         } else {
724                                 if (strip->packed()) {
725                                         strip_packer.remove (*strip);
726                                         strip->set_packed (false);
727                                 }
728                         }
729                 }
730         }
731         
732         if (Config->get_sync_all_route_ordering() && !ignore_route_reorder) {
733                 ignore_sync = true;
734                 Route::SyncOrderKeys (); // EMIT SIGNAL
735                 ignore_sync = false;
736         }
737
738         // Rebind all of the midi controls automatically
739         
740         if (auto_rebinding)
741                 auto_rebind_midi_controls ();
742
743 }
744
745 void
746 Mixer_UI::set_auto_rebinding( bool val )
747 {
748         if( val == TRUE )
749         {
750                 auto_rebinding = TRUE;
751                 Session::AutoBindingOff();
752         }
753         else
754         {
755                 auto_rebinding = FALSE;
756                 Session::AutoBindingOn();
757         }
758 }
759
760 void 
761 Mixer_UI::toggle_auto_rebinding() 
762 {
763         if (auto_rebinding)
764         {
765                 set_auto_rebinding( FALSE );
766         }
767         
768         else
769         {
770                 set_auto_rebinding( TRUE );
771         }
772
773         auto_rebind_midi_controls();
774 }
775
776 void 
777 Mixer_UI::auto_rebind_midi_controls () 
778 {
779         TreeModel::Children rows = track_model->children();
780         TreeModel::Children::iterator i;
781         int pos;
782
783         // Create bindings for all visible strips and remove those that are not visible
784         pos = 1;  // 0 is reserved for the master strip
785         for (i = rows.begin(); i != rows.end(); ++i) {
786                 MixerStrip* strip = (*i)[track_columns.strip];
787     
788                 if ( (*i)[track_columns.visible] == true ) {  // add bindings for
789                         // make the actual binding
790                         //cout<<"Auto Binding:  Visible Strip Found: "<<strip->name()<<endl;
791
792                         int controlValue = pos;
793                         if( strip->route()->is_master() ) {
794                                 controlValue = 0;
795                         }
796                         else {
797                                 pos++;
798                         }
799
800                         PBD::Controllable::CreateBinding ( strip->solo_button->get_controllable().get(), controlValue, 0);
801                         PBD::Controllable::CreateBinding ( strip->mute_button->get_controllable().get(), controlValue, 1);
802
803                         if( strip->is_audio_track() ) {
804                                 PBD::Controllable::CreateBinding ( strip->rec_enable_button->get_controllable().get(), controlValue, 2);
805                         }
806
807                         PBD::Controllable::CreateBinding ( strip->gpm.get_controllable().get(), controlValue, 3);
808                         PBD::Controllable::CreateBinding ( strip->panners.get_controllable().get(), controlValue, 4);
809
810                 }
811                 else {  // Remove any existing binding
812                         PBD::Controllable::DeleteBinding ( strip->solo_button->get_controllable().get() );
813                         PBD::Controllable::DeleteBinding ( strip->mute_button->get_controllable().get() );
814
815                         if( strip->is_audio_track() ) {
816                                 PBD::Controllable::DeleteBinding ( strip->rec_enable_button->get_controllable().get() );
817                         }
818
819                         PBD::Controllable::DeleteBinding ( strip->gpm.get_controllable().get() );
820                         PBD::Controllable::DeleteBinding ( strip->panners.get_controllable().get() ); // This only takes the first panner if there are multiples...
821                 }
822
823         } // for
824   
825 }
826
827 struct SignalOrderRouteSorter {
828     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
829             /* use of ">" forces the correct sort order */
830             return a->order_key (Mixer_UI::get_order_key()) < b->order_key (Mixer_UI::get_order_key());
831     }
832 };
833
834 void
835 Mixer_UI::initial_track_display ()
836 {
837         boost::shared_ptr<Session::RouteList> routes = session->get_routes();
838         Session::RouteList copy (*routes);
839         SignalOrderRouteSorter sorter;
840
841         copy.sort (sorter);
842         
843         no_track_list_redisplay = true;
844
845         track_model->clear ();
846
847         add_strip (copy);
848
849         no_track_list_redisplay = false;
850
851         redisplay_track_list ();
852 }
853
854 void
855 Mixer_UI::show_track_list_menu ()
856 {
857         if (track_menu == 0) {
858                 build_track_menu ();
859         }
860
861         track_menu->popup (1, gtk_get_current_event_time());
862 }
863
864 bool
865 Mixer_UI::track_display_button_press (GdkEventButton* ev)
866 {
867         if (Keyboard::is_context_menu_event (ev)) {
868                 show_track_list_menu ();
869                 return true;
870         }
871
872         TreeIter iter;
873         TreeModel::Path path;
874         TreeViewColumn* column;
875         int cellx;
876         int celly;
877         
878         if (!track_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
879                 return false;
880         }
881
882         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
883         case 0:
884                 /* allow normal processing to occur */
885                 return false;
886
887         case 1: /* visibility */
888
889                 if ((iter = track_model->get_iter (path))) {
890                         MixerStrip* strip = (*iter)[track_columns.strip];
891                         if (strip) {
892
893                                 if (!strip->route()->is_master() && !strip->route()->is_control()) {
894                                         bool visible = (*iter)[track_columns.visible];
895                                         (*iter)[track_columns.visible] = !visible;
896                                 }
897                         }
898                 }
899                 return true;
900
901         default:
902                 break;
903         }
904
905         return false;
906 }
907
908
909 void
910 Mixer_UI::build_track_menu ()
911 {
912         using namespace Menu_Helpers;
913         using namespace Gtk;
914
915         track_menu = new Menu;
916         track_menu->set_name ("ArdourContextMenu");
917         MenuList& items = track_menu->items();
918         
919         items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Mixer_UI::show_all_routes)));
920         items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Mixer_UI::hide_all_routes)));
921         items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
922         items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
923         items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun(*this, &Mixer_UI::show_all_audiobus)));
924         items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
925
926 }
927
928 void
929 Mixer_UI::strip_name_changed (MixerStrip* mx)
930 {
931         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::strip_name_changed), mx));
932         
933         TreeModel::Children rows = track_model->children();
934         TreeModel::Children::iterator i;
935         
936         for (i = rows.begin(); i != rows.end(); ++i) {
937                 if ((*i)[track_columns.strip] == mx) {
938                         (*i)[track_columns.text] = mx->route()->name();
939                         return;
940                 }
941         } 
942
943         error << _("track display list item for renamed strip not found!") << endmsg;
944 }
945
946
947 void
948 Mixer_UI::build_mix_group_context_menu ()
949 {
950         using namespace Gtk::Menu_Helpers;
951
952         mix_group_context_menu = new Menu;
953         mix_group_context_menu->set_name ("ArdourContextMenu");
954         MenuList& items = mix_group_context_menu->items();
955
956         items.push_back (MenuElem (_("Activate All"), mem_fun(*this, &Mixer_UI::activate_all_mix_groups)));
957         items.push_back (MenuElem (_("Disable All"), mem_fun(*this, &Mixer_UI::disable_all_mix_groups)));
958         items.push_back (SeparatorElem());
959         items.push_back (MenuElem (_("Add group"), mem_fun(*this, &Mixer_UI::new_mix_group)));
960         
961 }
962
963 bool
964 Mixer_UI::group_display_button_press (GdkEventButton* ev)
965 {
966         if (Keyboard::is_context_menu_event (ev)) {
967                 if (mix_group_context_menu == 0) {
968                         build_mix_group_context_menu ();
969                 }
970                 mix_group_context_menu->popup (1, ev->time);
971                 return true;
972         }
973
974
975         RouteGroup* group;
976         TreeIter iter;
977         TreeModel::Path path;
978         TreeViewColumn* column;
979         int cellx;
980         int celly;
981
982         if (!group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
983                 return false;
984         }
985
986         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
987         case 0:
988                 if (Keyboard::is_edit_event (ev)) {
989                         if ((iter = group_model->get_iter (path))) {
990                                 if ((group = (*iter)[group_columns.group]) != 0) {
991                                         // edit_mix_group (group);
992                                         return true;
993                                 }
994                         }
995                         
996                 } 
997                 break;
998
999         case 1:
1000                 if ((iter = group_model->get_iter (path))) {
1001                         bool active = (*iter)[group_columns.active];
1002                         (*iter)[group_columns.active] = !active;
1003                         return true;
1004                 }
1005                 break;
1006                 
1007         case 2:
1008                 if ((iter = group_model->get_iter (path))) {
1009                         bool visible = (*iter)[group_columns.visible];
1010                         (*iter)[group_columns.visible] = !visible;
1011                         return true;
1012                 }
1013                 break;
1014
1015         default:
1016                 break;
1017         }
1018         
1019         return false;
1020  }
1021
1022 void
1023 Mixer_UI::activate_all_mix_groups ()
1024 {
1025         Gtk::TreeModel::Children children = group_model->children();
1026         for(Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
1027                 (*iter)[group_columns.active] = true;
1028         }
1029 }
1030
1031 void
1032 Mixer_UI::disable_all_mix_groups ()
1033 {
1034         Gtk::TreeModel::Children children = group_model->children();
1035         for(Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
1036                 (*iter)[group_columns.active] = false;
1037         }
1038 }
1039
1040 void
1041 Mixer_UI::mix_groups_changed ()
1042 {
1043         ENSURE_GUI_THREAD (mem_fun (*this, &Mixer_UI::mix_groups_changed));
1044
1045         /* just rebuild the while thing */
1046
1047         group_model->clear ();
1048
1049         {
1050                 TreeModel::Row row;
1051                 row = *(group_model->append());
1052                 row[group_columns.active] = false;
1053                 row[group_columns.visible] = true;
1054                 row[group_columns.text] = (_("-all-"));
1055                 row[group_columns.group] = 0;
1056         }
1057
1058         session->foreach_mix_group (mem_fun (*this, &Mixer_UI::add_mix_group));
1059 }
1060
1061 void
1062 Mixer_UI::new_mix_group ()
1063 {
1064         session->add_mix_group ("");
1065 }
1066
1067 void
1068 Mixer_UI::remove_selected_mix_group ()
1069 {
1070         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1071         TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1072
1073         if (rows.empty()) {
1074                 return;
1075         }
1076
1077         TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1078         TreeIter iter;
1079         
1080         /* selection mode is single, so rows.begin() is it */
1081
1082         if ((iter = group_model->get_iter (*i))) {
1083
1084                 RouteGroup* rg = (*iter)[group_columns.group];
1085
1086                 if (rg) {
1087                         session->remove_mix_group (*rg);
1088                 }
1089         }
1090 }
1091
1092 void
1093 Mixer_UI::group_flags_changed (void* src, RouteGroup* group)
1094 {
1095         if (in_group_row_change) {
1096                 return;
1097         }
1098
1099         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::group_flags_changed), src, group));
1100
1101         /* force an update of any mixer strips that are using this group,
1102            otherwise mix group names don't change in mixer strips 
1103         */
1104
1105         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1106                 if ((*i)->mix_group() == group) {
1107                         (*i)->mix_group_changed(0);
1108                 }
1109         }
1110         
1111         TreeModel::iterator i;
1112         TreeModel::Children rows = group_model->children();
1113         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1114
1115         in_group_row_change = true;
1116         
1117         for (i = rows.begin(); i != rows.end(); ++i) {
1118                 if ((*i)[group_columns.group] == group) {
1119                         (*i)[group_columns.visible] = !group->is_hidden ();
1120                         (*i)[group_columns.active] = group->is_active ();
1121                         (*i)[group_columns.text] = group->name ();
1122                         break;
1123                 }
1124         }
1125
1126         in_group_row_change = false;
1127 }
1128
1129 void
1130 Mixer_UI::mix_group_name_edit (const Glib::ustring& path, const Glib::ustring& new_text)
1131 {
1132         RouteGroup* group;
1133         TreeIter iter;
1134
1135         if ((iter = group_model->get_iter (path))) {
1136         
1137                 if ((group = (*iter)[group_columns.group]) == 0) {
1138                         return;
1139                 }
1140                 
1141                 if (new_text != group->name()) {
1142                         group->set_name (new_text);
1143                 }
1144         }
1145 }
1146
1147 void 
1148 Mixer_UI::mix_group_row_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter)
1149 {
1150         RouteGroup* group;
1151
1152         if (in_group_row_change) {
1153                 return;
1154         }
1155
1156         if ((group = (*iter)[group_columns.group]) == 0) {
1157                 return;
1158         }
1159
1160         if ((*iter)[group_columns.visible]) {
1161                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1162                         if ((*i)->mix_group() == group) {
1163                                 show_strip (*i);
1164                         }
1165                 }
1166         } else {
1167                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1168                         if ((*i)->mix_group() == group) {
1169                                 hide_strip (*i);
1170                         }
1171                 }
1172         } 
1173
1174         bool active = (*iter)[group_columns.active];
1175         group->set_active (active, this);
1176
1177         Glib::ustring name = (*iter)[group_columns.text];
1178
1179         if (name != group->name()) {
1180                 group->set_name (name);
1181         }
1182
1183 }
1184
1185 void
1186 Mixer_UI::add_mix_group (RouteGroup* group)
1187
1188 {
1189         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::add_mix_group), group));
1190         bool focus = false;
1191
1192         in_group_row_change = true;
1193
1194         TreeModel::Row row = *(group_model->append());
1195         row[group_columns.active] = group->is_active();
1196         row[group_columns.visible] = true;
1197         row[group_columns.group] = group;
1198         if (!group->name().empty()) {
1199                 row[group_columns.text] = group->name();
1200         } else {
1201                 row[group_columns.text] = _("unnamed");
1202                 focus = true;
1203         }
1204
1205         group->FlagsChanged.connect (bind (mem_fun(*this, &Mixer_UI::group_flags_changed), group));
1206         
1207         if (focus) {
1208                 TreeViewColumn* col = group_display.get_column (0);
1209                 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
1210                 group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true);
1211         }
1212
1213         in_group_row_change = false;
1214 }
1215
1216 bool
1217 Mixer_UI::strip_scroller_button_release (GdkEventButton* ev)
1218 {
1219         using namespace Menu_Helpers;
1220
1221         if (Keyboard::is_context_menu_event (ev)) {
1222                 ARDOUR_UI::instance()->add_route (this);
1223                 return true;
1224         }
1225
1226         return false;
1227 }
1228
1229 void
1230 Mixer_UI::set_strip_width (Width w)
1231 {
1232         _strip_width = w;
1233
1234         for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1235                 (*i)->set_width (w, this);
1236         }
1237 }
1238
1239 void
1240 Mixer_UI::set_window_pos_and_size ()
1241 {
1242         resize (m_width, m_height);
1243         move (m_root_x, m_root_y);
1244 }
1245
1246         void
1247 Mixer_UI::get_window_pos_and_size ()
1248 {
1249         get_position(m_root_x, m_root_y);
1250         get_size(m_width, m_height);
1251 }
1252
1253 int
1254 Mixer_UI::set_state (const XMLNode& node)
1255 {
1256         const XMLProperty* prop;
1257         XMLNode* geometry;
1258         
1259         if ((geometry = find_named_node (node, "geometry")) == 0) {
1260
1261                 m_width = default_width;
1262                 m_height = default_height;
1263                 m_root_x = 1;
1264                 m_root_y = 1;
1265
1266         } else {
1267
1268                 m_width = atoi(geometry->property("x_size")->value().c_str());
1269                 m_height = atoi(geometry->property("y_size")->value().c_str());
1270                 m_root_x = atoi(geometry->property("x_pos")->value().c_str());
1271                 m_root_y = atoi(geometry->property("y_pos")->value().c_str());
1272         }
1273
1274         set_window_pos_and_size ();
1275
1276         if ((prop = node.property ("narrow-strips"))) {
1277                 if (prop->value() == "yes") {
1278                         set_strip_width (Narrow);
1279                 } else {
1280                         set_strip_width (Wide);
1281                 }
1282         }
1283
1284         if ((prop = node.property ("show-mixer"))) {
1285                 if (prop->value() == "yes") {
1286                        _visible = true;
1287                 }
1288         }
1289
1290         return 0;
1291 }
1292
1293 XMLNode&
1294 Mixer_UI::get_state (void)
1295 {
1296         XMLNode* node = new XMLNode ("Mixer");
1297
1298         if (is_realized()) {
1299                 Glib::RefPtr<Gdk::Window> win = get_window();
1300         
1301                 get_window_pos_and_size ();
1302
1303                 XMLNode* geometry = new XMLNode ("geometry");
1304                 char buf[32];
1305                 snprintf(buf, sizeof(buf), "%d", m_width);
1306                 geometry->add_property(X_("x_size"), string(buf));
1307                 snprintf(buf, sizeof(buf), "%d", m_height);
1308                 geometry->add_property(X_("y_size"), string(buf));
1309                 snprintf(buf, sizeof(buf), "%d", m_root_x);
1310                 geometry->add_property(X_("x_pos"), string(buf));
1311                 snprintf(buf, sizeof(buf), "%d", m_root_y);
1312                 geometry->add_property(X_("y_pos"), string(buf));
1313                 
1314                 // written only for compatibility, they are not used.
1315                 snprintf(buf, sizeof(buf), "%d", 0);
1316                 geometry->add_property(X_("x_off"), string(buf));
1317                 snprintf(buf, sizeof(buf), "%d", 0);
1318                 geometry->add_property(X_("y_off"), string(buf));
1319
1320                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&rhs_pane1)->gobj()));
1321                 geometry->add_property(X_("mixer_rhs_pane1_pos"), string(buf));
1322                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&list_hpane)->gobj()));
1323                 geometry->add_property(X_("mixer_list_hpane_pos"), string(buf));
1324
1325                 node->add_child_nocopy (*geometry);
1326         }
1327
1328         node->add_property ("narrow-strips", _strip_width == Narrow ? "yes" : "no");
1329
1330         node->add_property ("show-mixer", _visible ? "yes" : "no");
1331
1332         return *node;
1333 }
1334
1335
1336 void 
1337 Mixer_UI::pane_allocation_handler (Allocation& alloc, Gtk::Paned* which)
1338 {
1339         int pos;
1340         XMLProperty* prop = 0;
1341         char buf[32];
1342         XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
1343         XMLNode* geometry;
1344         int width, height;
1345         static int32_t done[3] = { 0, 0, 0 };
1346
1347         if ((geometry = find_named_node (*node, "geometry")) == 0) {
1348                 width = default_width;
1349                 height = default_height;
1350         } else {
1351                 width = atoi(geometry->property("x_size")->value());
1352                 height = atoi(geometry->property("y_size")->value());
1353         }
1354
1355         if (which == static_cast<Gtk::Paned*> (&rhs_pane1)) {
1356
1357                 if (done[0]) {
1358                         return;
1359                 }
1360
1361                 if (!geometry || (prop = geometry->property("mixer_rhs_pane1_pos")) == 0) {
1362                         pos = height / 3;
1363                         snprintf (buf, sizeof(buf), "%d", pos);
1364                 } else {
1365                         pos = atoi (prop->value());
1366                 }
1367
1368                 if ((done[0] = GTK_WIDGET(rhs_pane1.gobj())->allocation.height > pos)) {
1369                         rhs_pane1.set_position (pos);
1370                 }
1371
1372         } else if (which == static_cast<Gtk::Paned*> (&list_hpane)) {
1373
1374                 if (done[2]) {
1375                         return;
1376                 }
1377
1378                 if (!geometry || (prop = geometry->property("mixer_list_hpane_pos")) == 0) {
1379                         pos = 75;
1380                         snprintf (buf, sizeof(buf), "%d", pos);
1381                 } else {
1382                         pos = atoi (prop->value());
1383                 }
1384
1385                 if ((done[2] = GTK_WIDGET(list_hpane.gobj())->allocation.width > pos)) {
1386                         list_hpane.set_position (pos);
1387                 }
1388         }
1389 }
1390
1391 bool
1392 Mixer_UI::on_key_press_event (GdkEventKey* ev)
1393 {
1394         return key_press_focus_accelerator_handler (*this, ev);
1395 }