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