Fix mismatched types (warnings).
[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         ignore_route_reorder = true;
669         redisplay_track_list ();
670         ignore_route_reorder = false;
671 }
672
673 void
674 Mixer_UI::redisplay_track_list ()
675 {
676         TreeModel::Children rows = track_model->children();
677         TreeModel::Children::iterator i;
678         long order;
679
680         if (no_track_list_redisplay) {
681                 return;
682         }
683
684         for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
685                 MixerStrip* strip = (*i)[track_columns.strip];
686
687                 if (strip == 0) {
688                         /* we're in the middle of changing a row, don't worry */
689                         continue;
690                 }
691
692                 bool visible = (*i)[track_columns.visible];
693
694                 if (visible) {
695                         strip->set_marked_for_display (true);
696                         strip->route()->set_order_key (N_("signal"), order);
697
698                         if (!ignore_route_reorder) {
699                                 strip->route()->set_order_key (get_order_key(), order);
700                         } 
701
702                         if (strip->packed()) {
703
704                                 if (strip->route()->is_master() || strip->route()->is_control()) {
705                                         out_packer.reorder_child (*strip, -1);
706                                 } else {
707                                         strip_packer.reorder_child (*strip, -1); /* put at end */
708                                 }
709
710                         } else {
711
712                                 if (strip->route()->is_master() || strip->route()->is_control()) {
713                                         out_packer.pack_start (*strip, false, false);
714                                 } else {
715                                         strip_packer.pack_start (*strip, false, false);
716                                 }
717                                 strip->set_packed (true);
718                                 //strip->show();
719                         }
720
721                 } else {
722
723                         if (strip->route()->is_master() || strip->route()->is_control()) {
724                                 /* do nothing, these cannot be hidden */
725                         } else {
726                                 if (strip->packed()) {
727                                         strip_packer.remove (*strip);
728                                         strip->set_packed (false);
729                                 }
730                         }
731                 }
732         }
733         
734         if (Config->get_sync_all_route_ordering() && !ignore_route_reorder) {
735                 ignore_sync = true;
736                 Route::SyncOrderKeys (); // EMIT SIGNAL
737                 ignore_sync = false;
738         }
739
740         // Rebind all of the midi controls automatically
741         
742         if (auto_rebinding)
743                 auto_rebind_midi_controls ();
744
745 }
746
747 void
748 Mixer_UI::set_auto_rebinding( bool val )
749 {
750         if( val == TRUE )
751         {
752                 auto_rebinding = TRUE;
753                 Session::AutoBindingOff();
754         }
755         else
756         {
757                 auto_rebinding = FALSE;
758                 Session::AutoBindingOn();
759         }
760 }
761
762 void 
763 Mixer_UI::toggle_auto_rebinding() 
764 {
765         if (auto_rebinding)
766         {
767                 set_auto_rebinding( FALSE );
768         }
769         
770         else
771         {
772                 set_auto_rebinding( TRUE );
773         }
774
775         auto_rebind_midi_controls();
776 }
777
778 void 
779 Mixer_UI::auto_rebind_midi_controls () 
780 {
781         TreeModel::Children rows = track_model->children();
782         TreeModel::Children::iterator i;
783         int pos;
784
785         // Create bindings for all visible strips and remove those that are not visible
786         pos = 1;  // 0 is reserved for the master strip
787         for (i = rows.begin(); i != rows.end(); ++i) {
788                 MixerStrip* strip = (*i)[track_columns.strip];
789     
790                 if ( (*i)[track_columns.visible] == true ) {  // add bindings for
791                         // make the actual binding
792                         //cout<<"Auto Binding:  Visible Strip Found: "<<strip->name()<<endl;
793
794                         int controlValue = pos;
795                         if( strip->route()->is_master() ) {
796                                 controlValue = 0;
797                         }
798                         else {
799                                 pos++;
800                         }
801
802                         PBD::Controllable::CreateBinding ( strip->solo_button->get_controllable().get(), controlValue, 0);
803                         PBD::Controllable::CreateBinding ( strip->mute_button->get_controllable().get(), controlValue, 1);
804
805                         if( strip->is_audio_track() ) {
806                                 PBD::Controllable::CreateBinding ( strip->rec_enable_button->get_controllable().get(), controlValue, 2);
807                         }
808
809                         PBD::Controllable::CreateBinding ( strip->gpm.get_controllable().get(), controlValue, 3);
810                         PBD::Controllable::CreateBinding ( strip->panners.get_controllable().get(), controlValue, 4);
811
812                 }
813                 else {  // Remove any existing binding
814                         PBD::Controllable::DeleteBinding ( strip->solo_button->get_controllable().get() );
815                         PBD::Controllable::DeleteBinding ( strip->mute_button->get_controllable().get() );
816
817                         if( strip->is_audio_track() ) {
818                                 PBD::Controllable::DeleteBinding ( strip->rec_enable_button->get_controllable().get() );
819                         }
820
821                         PBD::Controllable::DeleteBinding ( strip->gpm.get_controllable().get() );
822                         PBD::Controllable::DeleteBinding ( strip->panners.get_controllable().get() ); // This only takes the first panner if there are multiples...
823                 }
824
825         } // for
826   
827 }
828
829 struct SignalOrderRouteSorter {
830     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
831             /* use of ">" forces the correct sort order */
832             return a->order_key (Mixer_UI::get_order_key()) < b->order_key (Mixer_UI::get_order_key());
833     }
834 };
835
836 void
837 Mixer_UI::initial_track_display ()
838 {
839         boost::shared_ptr<Session::RouteList> routes = session->get_routes();
840         Session::RouteList copy (*routes);
841         SignalOrderRouteSorter sorter;
842
843         copy.sort (sorter);
844         
845         no_track_list_redisplay = true;
846
847         track_model->clear ();
848
849         add_strip (copy);
850
851         no_track_list_redisplay = false;
852
853         redisplay_track_list ();
854 }
855
856 void
857 Mixer_UI::show_track_list_menu ()
858 {
859         if (track_menu == 0) {
860                 build_track_menu ();
861         }
862
863         track_menu->popup (1, gtk_get_current_event_time());
864 }
865
866 bool
867 Mixer_UI::track_display_button_press (GdkEventButton* ev)
868 {
869         if (Keyboard::is_context_menu_event (ev)) {
870                 show_track_list_menu ();
871                 return true;
872         }
873
874         TreeIter iter;
875         TreeModel::Path path;
876         TreeViewColumn* column;
877         int cellx;
878         int celly;
879         
880         if (!track_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
881                 return false;
882         }
883
884         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
885         case 0:
886                 /* allow normal processing to occur */
887                 return false;
888
889         case 1: /* visibility */
890
891                 if ((iter = track_model->get_iter (path))) {
892                         MixerStrip* strip = (*iter)[track_columns.strip];
893                         if (strip) {
894
895                                 if (!strip->route()->is_master() && !strip->route()->is_control()) {
896                                         bool visible = (*iter)[track_columns.visible];
897                                         (*iter)[track_columns.visible] = !visible;
898                                 }
899                         }
900                 }
901                 return true;
902
903         default:
904                 break;
905         }
906
907         return false;
908 }
909
910
911 void
912 Mixer_UI::build_track_menu ()
913 {
914         using namespace Menu_Helpers;
915         using namespace Gtk;
916
917         track_menu = new Menu;
918         track_menu->set_name ("ArdourContextMenu");
919         MenuList& items = track_menu->items();
920         
921         items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Mixer_UI::show_all_routes)));
922         items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Mixer_UI::hide_all_routes)));
923         items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
924         items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
925         items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun(*this, &Mixer_UI::show_all_audiobus)));
926         items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
927
928 }
929
930 void
931 Mixer_UI::strip_name_changed (MixerStrip* mx)
932 {
933         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::strip_name_changed), mx));
934         
935         TreeModel::Children rows = track_model->children();
936         TreeModel::Children::iterator i;
937         
938         for (i = rows.begin(); i != rows.end(); ++i) {
939                 if ((*i)[track_columns.strip] == mx) {
940                         (*i)[track_columns.text] = mx->route()->name();
941                         return;
942                 }
943         } 
944
945         error << _("track display list item for renamed strip not found!") << endmsg;
946 }
947
948
949 void
950 Mixer_UI::build_mix_group_context_menu ()
951 {
952         using namespace Gtk::Menu_Helpers;
953
954         mix_group_context_menu = new Menu;
955         mix_group_context_menu->set_name ("ArdourContextMenu");
956         MenuList& items = mix_group_context_menu->items();
957
958         items.push_back (MenuElem (_("Activate All"), mem_fun(*this, &Mixer_UI::activate_all_mix_groups)));
959         items.push_back (MenuElem (_("Disable All"), mem_fun(*this, &Mixer_UI::disable_all_mix_groups)));
960         items.push_back (SeparatorElem());
961         items.push_back (MenuElem (_("Add group"), mem_fun(*this, &Mixer_UI::new_mix_group)));
962         
963 }
964
965 bool
966 Mixer_UI::group_display_button_press (GdkEventButton* ev)
967 {
968         if (Keyboard::is_context_menu_event (ev)) {
969                 if (mix_group_context_menu == 0) {
970                         build_mix_group_context_menu ();
971                 }
972                 mix_group_context_menu->popup (1, ev->time);
973                 return true;
974         }
975
976
977         RouteGroup* group;
978         TreeIter iter;
979         TreeModel::Path path;
980         TreeViewColumn* column;
981         int cellx;
982         int celly;
983
984         if (!group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
985                 return false;
986         }
987
988         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
989         case 0:
990                 if (Keyboard::is_edit_event (ev)) {
991                         if ((iter = group_model->get_iter (path))) {
992                                 if ((group = (*iter)[group_columns.group]) != 0) {
993                                         // edit_mix_group (group);
994                                         return true;
995                                 }
996                         }
997                         
998                 } 
999                 break;
1000
1001         case 1:
1002                 if ((iter = group_model->get_iter (path))) {
1003                         bool active = (*iter)[group_columns.active];
1004                         (*iter)[group_columns.active] = !active;
1005                         return true;
1006                 }
1007                 break;
1008                 
1009         case 2:
1010                 if ((iter = group_model->get_iter (path))) {
1011                         bool visible = (*iter)[group_columns.visible];
1012                         (*iter)[group_columns.visible] = !visible;
1013                         return true;
1014                 }
1015                 break;
1016
1017         default:
1018                 break;
1019         }
1020         
1021         return false;
1022  }
1023
1024 void
1025 Mixer_UI::activate_all_mix_groups ()
1026 {
1027         Gtk::TreeModel::Children children = group_model->children();
1028         for(Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
1029                 (*iter)[group_columns.active] = true;
1030         }
1031 }
1032
1033 void
1034 Mixer_UI::disable_all_mix_groups ()
1035 {
1036         Gtk::TreeModel::Children children = group_model->children();
1037         for(Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
1038                 (*iter)[group_columns.active] = false;
1039         }
1040 }
1041
1042 void
1043 Mixer_UI::mix_groups_changed ()
1044 {
1045         ENSURE_GUI_THREAD (mem_fun (*this, &Mixer_UI::mix_groups_changed));
1046
1047         /* just rebuild the while thing */
1048
1049         group_model->clear ();
1050
1051         {
1052                 TreeModel::Row row;
1053                 row = *(group_model->append());
1054                 row[group_columns.active] = false;
1055                 row[group_columns.visible] = true;
1056                 row[group_columns.text] = (_("-all-"));
1057                 row[group_columns.group] = 0;
1058         }
1059
1060         session->foreach_mix_group (mem_fun (*this, &Mixer_UI::add_mix_group));
1061 }
1062
1063 void
1064 Mixer_UI::new_mix_group ()
1065 {
1066         session->add_mix_group ("");
1067 }
1068
1069 void
1070 Mixer_UI::remove_selected_mix_group ()
1071 {
1072         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1073         TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1074
1075         if (rows.empty()) {
1076                 return;
1077         }
1078
1079         TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1080         TreeIter iter;
1081         
1082         /* selection mode is single, so rows.begin() is it */
1083
1084         if ((iter = group_model->get_iter (*i))) {
1085
1086                 RouteGroup* rg = (*iter)[group_columns.group];
1087
1088                 if (rg) {
1089                         session->remove_mix_group (*rg);
1090                 }
1091         }
1092 }
1093
1094 void
1095 Mixer_UI::group_flags_changed (void* src, RouteGroup* group)
1096 {
1097         if (in_group_row_change) {
1098                 return;
1099         }
1100
1101         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::group_flags_changed), src, group));
1102
1103         /* force an update of any mixer strips that are using this group,
1104            otherwise mix group names don't change in mixer strips 
1105         */
1106
1107         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1108                 if ((*i)->mix_group() == group) {
1109                         (*i)->mix_group_changed(0);
1110                 }
1111         }
1112         
1113         TreeModel::iterator i;
1114         TreeModel::Children rows = group_model->children();
1115         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1116
1117         in_group_row_change = true;
1118         
1119         for (i = rows.begin(); i != rows.end(); ++i) {
1120                 if ((*i)[group_columns.group] == group) {
1121                         (*i)[group_columns.visible] = !group->is_hidden ();
1122                         (*i)[group_columns.active] = group->is_active ();
1123                         (*i)[group_columns.text] = group->name ();
1124                         break;
1125                 }
1126         }
1127
1128         in_group_row_change = false;
1129 }
1130
1131 void
1132 Mixer_UI::mix_group_name_edit (const Glib::ustring& path, const Glib::ustring& new_text)
1133 {
1134         RouteGroup* group;
1135         TreeIter iter;
1136
1137         if ((iter = group_model->get_iter (path))) {
1138         
1139                 if ((group = (*iter)[group_columns.group]) == 0) {
1140                         return;
1141                 }
1142                 
1143                 if (new_text != group->name()) {
1144                         group->set_name (new_text);
1145                 }
1146         }
1147 }
1148
1149 void 
1150 Mixer_UI::mix_group_row_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter)
1151 {
1152         RouteGroup* group;
1153
1154         if (in_group_row_change) {
1155                 return;
1156         }
1157
1158         if ((group = (*iter)[group_columns.group]) == 0) {
1159                 return;
1160         }
1161
1162         if ((*iter)[group_columns.visible]) {
1163                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1164                         if ((*i)->mix_group() == group) {
1165                                 show_strip (*i);
1166                         }
1167                 }
1168         } else {
1169                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1170                         if ((*i)->mix_group() == group) {
1171                                 hide_strip (*i);
1172                         }
1173                 }
1174         } 
1175
1176         bool active = (*iter)[group_columns.active];
1177         group->set_active (active, this);
1178
1179         Glib::ustring name = (*iter)[group_columns.text];
1180
1181         if (name != group->name()) {
1182                 group->set_name (name);
1183         }
1184
1185 }
1186
1187 void
1188 Mixer_UI::add_mix_group (RouteGroup* group)
1189
1190 {
1191         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::add_mix_group), group));
1192         bool focus = false;
1193
1194         in_group_row_change = true;
1195
1196         TreeModel::Row row = *(group_model->append());
1197         row[group_columns.active] = group->is_active();
1198         row[group_columns.visible] = true;
1199         row[group_columns.group] = group;
1200         if (!group->name().empty()) {
1201                 row[group_columns.text] = group->name();
1202         } else {
1203                 row[group_columns.text] = _("unnamed");
1204                 focus = true;
1205         }
1206
1207         group->FlagsChanged.connect (bind (mem_fun(*this, &Mixer_UI::group_flags_changed), group));
1208         
1209         if (focus) {
1210                 TreeViewColumn* col = group_display.get_column (0);
1211                 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
1212                 group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true);
1213         }
1214
1215         in_group_row_change = false;
1216 }
1217
1218 bool
1219 Mixer_UI::strip_scroller_button_release (GdkEventButton* ev)
1220 {
1221         using namespace Menu_Helpers;
1222
1223         if (Keyboard::is_context_menu_event (ev)) {
1224                 ARDOUR_UI::instance()->add_route (this);
1225                 return true;
1226         }
1227
1228         return false;
1229 }
1230
1231 void
1232 Mixer_UI::set_strip_width (Width w)
1233 {
1234         _strip_width = w;
1235
1236         for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1237                 (*i)->set_width (w, this);
1238         }
1239 }
1240
1241 void
1242 Mixer_UI::set_window_pos_and_size ()
1243 {
1244         resize (m_width, m_height);
1245         move (m_root_x, m_root_y);
1246 }
1247
1248         void
1249 Mixer_UI::get_window_pos_and_size ()
1250 {
1251         get_position(m_root_x, m_root_y);
1252         get_size(m_width, m_height);
1253 }
1254
1255 int
1256 Mixer_UI::set_state (const XMLNode& node)
1257 {
1258         const XMLProperty* prop;
1259         XMLNode* geometry;
1260         
1261         if ((geometry = find_named_node (node, "geometry")) == 0) {
1262
1263                 m_width = default_width;
1264                 m_height = default_height;
1265                 m_root_x = 1;
1266                 m_root_y = 1;
1267
1268         } else {
1269
1270                 m_width = atoi(geometry->property("x-size")->value().c_str());
1271                 m_height = atoi(geometry->property("y-size")->value().c_str());
1272                 m_root_x = atoi(geometry->property("x-pos")->value().c_str());
1273                 m_root_y = atoi(geometry->property("y-pos")->value().c_str());
1274         }
1275
1276         set_window_pos_and_size ();
1277
1278         if ((prop = node.property ("narrow-strips"))) {
1279                 if (prop->value() == "yes") {
1280                         set_strip_width (Narrow);
1281                 } else {
1282                         set_strip_width (Wide);
1283                 }
1284         }
1285
1286         if ((prop = node.property ("show-mixer"))) {
1287                 if (prop->value() == "yes") {
1288                        _visible = true;
1289                 }
1290         }
1291
1292         return 0;
1293 }
1294
1295 XMLNode&
1296 Mixer_UI::get_state (void)
1297 {
1298         XMLNode* node = new XMLNode ("Mixer");
1299
1300         if (is_realized()) {
1301                 Glib::RefPtr<Gdk::Window> win = get_window();
1302         
1303                 get_window_pos_and_size ();
1304
1305                 XMLNode* geometry = new XMLNode ("geometry");
1306                 char buf[32];
1307                 snprintf(buf, sizeof(buf), "%d", m_width);
1308                 geometry->add_property(X_("x_size"), string(buf));
1309                 snprintf(buf, sizeof(buf), "%d", m_height);
1310                 geometry->add_property(X_("y_size"), string(buf));
1311                 snprintf(buf, sizeof(buf), "%d", m_root_x);
1312                 geometry->add_property(X_("x_pos"), string(buf));
1313                 snprintf(buf, sizeof(buf), "%d", m_root_y);
1314                 geometry->add_property(X_("y_pos"), string(buf));
1315                 
1316                 // written only for compatibility, they are not used.
1317                 snprintf(buf, sizeof(buf), "%d", 0);
1318                 geometry->add_property(X_("x_off"), string(buf));
1319                 snprintf(buf, sizeof(buf), "%d", 0);
1320                 geometry->add_property(X_("y_off"), string(buf));
1321
1322                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&rhs_pane1)->gobj()));
1323                 geometry->add_property(X_("mixer_rhs_pane1_pos"), string(buf));
1324                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&list_hpane)->gobj()));
1325                 geometry->add_property(X_("mixer_list_hpane_pos"), string(buf));
1326
1327                 node->add_child_nocopy (*geometry);
1328         }
1329
1330         node->add_property ("narrow-strips", _strip_width == Narrow ? "yes" : "no");
1331
1332         node->add_property ("show-mixer", _visible ? "yes" : "no");
1333
1334         return *node;
1335 }
1336
1337
1338 void 
1339 Mixer_UI::pane_allocation_handler (Allocation& alloc, Gtk::Paned* which)
1340 {
1341         int pos;
1342         XMLProperty* prop = 0;
1343         char buf[32];
1344         XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
1345         XMLNode* geometry;
1346         int width, height;
1347         static int32_t done[3] = { 0, 0, 0 };
1348
1349         if ((geometry = find_named_node (*node, "geometry")) == 0) {
1350                 width = default_width;
1351                 height = default_height;
1352         } else {
1353                 width = atoi(geometry->property("x-size")->value());
1354                 height = atoi(geometry->property("y-size")->value());
1355         }
1356
1357         if (which == static_cast<Gtk::Paned*> (&rhs_pane1)) {
1358
1359                 if (done[0]) {
1360                         return;
1361                 }
1362
1363                 if (!geometry || (prop = geometry->property("mixer-rhs-pane1-pos")) == 0) {
1364                         pos = height / 3;
1365                         snprintf (buf, sizeof(buf), "%d", pos);
1366                 } else {
1367                         pos = atoi (prop->value());
1368                 }
1369
1370                 if ((done[0] = GTK_WIDGET(rhs_pane1.gobj())->allocation.height > pos)) {
1371                         rhs_pane1.set_position (pos);
1372                 }
1373
1374         } else if (which == static_cast<Gtk::Paned*> (&list_hpane)) {
1375
1376                 if (done[2]) {
1377                         return;
1378                 }
1379
1380                 if (!geometry || (prop = geometry->property("mixer-list-hpane-pos")) == 0) {
1381                         pos = 75;
1382                         snprintf (buf, sizeof(buf), "%d", pos);
1383                 } else {
1384                         pos = atoi (prop->value());
1385                 }
1386
1387                 if ((done[2] = GTK_WIDGET(list_hpane.gobj())->allocation.width > pos)) {
1388                         list_hpane.set_position (pos);
1389                 }
1390         }
1391 }
1392
1393 bool
1394 Mixer_UI::on_key_press_event (GdkEventKey* ev)
1395 {
1396         return key_press_focus_accelerator_handler (*this, ev);
1397 }