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