Make the wiimote code appear in the source package
[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 #ifdef GTKOSX
926                                 track_display.queue_draw();
927 #endif
928                         }
929                 }
930                 return true;
931
932         default:
933                 break;
934         }
935
936         return false;
937 }
938
939
940 void
941 Mixer_UI::build_track_menu ()
942 {
943         using namespace Menu_Helpers;
944         using namespace Gtk;
945
946         track_menu = new Menu;
947         track_menu->set_name ("ArdourContextMenu");
948         MenuList& items = track_menu->items();
949         
950         items.push_back (MenuElem (_("Show All"), mem_fun(*this, &Mixer_UI::show_all_routes)));
951         items.push_back (MenuElem (_("Hide All"), mem_fun(*this, &Mixer_UI::hide_all_routes)));
952         items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
953         items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
954         items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun(*this, &Mixer_UI::show_all_audiobus)));
955         items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
956
957 }
958
959 void
960 Mixer_UI::strip_name_changed (void* src, MixerStrip* mx)
961 {
962         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::strip_name_changed), src, mx));
963         
964         TreeModel::Children rows = track_model->children();
965         TreeModel::Children::iterator i;
966         
967         for (i = rows.begin(); i != rows.end(); ++i) {
968                 if ((*i)[track_columns.strip] == mx) {
969                         (*i)[track_columns.text] = mx->route()->name();
970                         return;
971                 }
972         } 
973
974         error << _("track display list item for renamed strip not found!") << endmsg;
975 }
976
977
978 void
979 Mixer_UI::build_mix_group_context_menu ()
980 {
981         using namespace Gtk::Menu_Helpers;
982
983         mix_group_context_menu = new Menu;
984         mix_group_context_menu->set_name ("ArdourContextMenu");
985         MenuList& items = mix_group_context_menu->items();
986
987         items.push_back (MenuElem (_("Activate All"), mem_fun(*this, &Mixer_UI::activate_all_mix_groups)));
988         items.push_back (MenuElem (_("Disable All"), mem_fun(*this, &Mixer_UI::disable_all_mix_groups)));
989         items.push_back (SeparatorElem());
990         items.push_back (MenuElem (_("Add group"), mem_fun(*this, &Mixer_UI::new_mix_group)));
991         
992 }
993
994 bool
995 Mixer_UI::group_display_button_press (GdkEventButton* ev)
996 {
997         if (Keyboard::is_context_menu_event (ev)) {
998                 if (mix_group_context_menu == 0) {
999                         build_mix_group_context_menu ();
1000                 }
1001                 mix_group_context_menu->popup (1, ev->time);
1002                 return true;
1003         }
1004
1005
1006         RouteGroup* group;
1007         TreeIter iter;
1008         TreeModel::Path path;
1009         TreeViewColumn* column;
1010         int cellx;
1011         int celly;
1012
1013         if (!group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
1014                 return false;
1015         }
1016
1017         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
1018         case 0:
1019                 if (Keyboard::is_edit_event (ev)) {
1020                         if ((iter = group_model->get_iter (path))) {
1021                                 if ((group = (*iter)[group_columns.group]) != 0) {
1022                                         // edit_mix_group (group);
1023 #ifdef GTKOSX
1024                                         group_display.queue_draw();
1025 #endif
1026                                         return true;
1027                                 }
1028                         }
1029                         
1030                 } 
1031                 break;
1032
1033         case 1:
1034                 if ((iter = group_model->get_iter (path))) {
1035                         bool active = (*iter)[group_columns.active];
1036                         (*iter)[group_columns.active] = !active;
1037 #ifdef GTKOSX
1038                         group_display.queue_draw();
1039 #endif
1040                         return true;
1041                 }
1042                 break;
1043                 
1044         case 2:
1045                 if ((iter = group_model->get_iter (path))) {
1046                         bool visible = (*iter)[group_columns.visible];
1047                         (*iter)[group_columns.visible] = !visible;
1048 #ifdef GTKOSX
1049                         group_display.queue_draw();
1050 #endif
1051                         return true;
1052                 }
1053                 break;
1054
1055         default:
1056                 break;
1057         }
1058         
1059         return false;
1060  }
1061
1062 void
1063 Mixer_UI::activate_all_mix_groups ()
1064 {
1065         Gtk::TreeModel::Children children = group_model->children();
1066         for(Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
1067                 (*iter)[group_columns.active] = true;
1068         }
1069 }
1070
1071 void
1072 Mixer_UI::disable_all_mix_groups ()
1073 {
1074         Gtk::TreeModel::Children children = group_model->children();
1075         for(Gtk::TreeModel::Children::iterator iter = children.begin(); iter != children.end(); ++iter) {
1076                 (*iter)[group_columns.active] = false;
1077         }
1078 }
1079
1080 void
1081 Mixer_UI::mix_groups_changed ()
1082 {
1083         ENSURE_GUI_THREAD (mem_fun (*this, &Mixer_UI::mix_groups_changed));
1084
1085         /* just rebuild the while thing */
1086
1087         group_model->clear ();
1088
1089         {
1090                 TreeModel::Row row;
1091                 row = *(group_model->append());
1092                 row[group_columns.active] = false;
1093                 row[group_columns.visible] = true;
1094                 row[group_columns.text] = (_("-all-"));
1095                 row[group_columns.group] = 0;
1096         }
1097
1098         session->foreach_mix_group (mem_fun (*this, &Mixer_UI::add_mix_group));
1099 }
1100
1101 void
1102 Mixer_UI::new_mix_group ()
1103 {
1104         session->add_mix_group ("");
1105 }
1106
1107 void
1108 Mixer_UI::remove_selected_mix_group ()
1109 {
1110         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1111         TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1112
1113         if (rows.empty()) {
1114                 return;
1115         }
1116
1117         TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1118         TreeIter iter;
1119         
1120         /* selection mode is single, so rows.begin() is it */
1121
1122         if ((iter = group_model->get_iter (*i))) {
1123
1124                 RouteGroup* rg = (*iter)[group_columns.group];
1125
1126                 if (rg) {
1127                         session->remove_mix_group (*rg);
1128                 }
1129         }
1130 }
1131
1132 void
1133 Mixer_UI::group_flags_changed (void* src, RouteGroup* group)
1134 {
1135         if (in_group_row_change) {
1136                 return;
1137         }
1138
1139         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::group_flags_changed), src, group));
1140
1141         /* force an update of any mixer strips that are using this group,
1142            otherwise mix group names don't change in mixer strips 
1143         */
1144
1145         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1146                 if ((*i)->mix_group() == group) {
1147                         (*i)->mix_group_changed(0);
1148                 }
1149         }
1150         
1151         TreeModel::iterator i;
1152         TreeModel::Children rows = group_model->children();
1153         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1154
1155         in_group_row_change = true;
1156         
1157         for (i = rows.begin(); i != rows.end(); ++i) {
1158                 if ((*i)[group_columns.group] == group) {
1159                         (*i)[group_columns.visible] = !group->is_hidden ();
1160                         (*i)[group_columns.active] = group->is_active ();
1161                         (*i)[group_columns.text] = group->name ();
1162                         break;
1163                 }
1164         }
1165
1166         in_group_row_change = false;
1167 }
1168
1169 void
1170 Mixer_UI::mix_group_name_edit (const Glib::ustring& path, const Glib::ustring& new_text)
1171 {
1172         RouteGroup* group;
1173         TreeIter iter;
1174
1175         if ((iter = group_model->get_iter (path))) {
1176         
1177                 if ((group = (*iter)[group_columns.group]) == 0) {
1178                         return;
1179                 }
1180                 
1181                 if (new_text != group->name()) {
1182                         group->set_name (new_text);
1183                 }
1184         }
1185 }
1186
1187 void 
1188 Mixer_UI::mix_group_row_change (const Gtk::TreeModel::Path& path,const Gtk::TreeModel::iterator& iter)
1189 {
1190         RouteGroup* group;
1191
1192         if (in_group_row_change) {
1193                 return;
1194         }
1195
1196         if ((group = (*iter)[group_columns.group]) == 0) {
1197                 return;
1198         }
1199
1200         if ((*iter)[group_columns.visible]) {
1201                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1202                         if ((*i)->mix_group() == group) {
1203                                 show_strip (*i);
1204                         }
1205                 }
1206         } else {
1207                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1208                         if ((*i)->mix_group() == group) {
1209                                 hide_strip (*i);
1210                         }
1211                 }
1212         } 
1213
1214         bool active = (*iter)[group_columns.active];
1215         group->set_active (active, this);
1216
1217         Glib::ustring name = (*iter)[group_columns.text];
1218
1219         if (name != group->name()) {
1220                 group->set_name (name);
1221         }
1222
1223 }
1224
1225 void
1226 Mixer_UI::add_mix_group (RouteGroup* group)
1227
1228 {
1229         ENSURE_GUI_THREAD(bind (mem_fun(*this, &Mixer_UI::add_mix_group), group));
1230         bool focus = false;
1231
1232         in_group_row_change = true;
1233
1234         TreeModel::Row row = *(group_model->append());
1235         row[group_columns.active] = group->is_active();
1236         row[group_columns.visible] = true;
1237         row[group_columns.group] = group;
1238         if (!group->name().empty()) {
1239                 row[group_columns.text] = group->name();
1240         } else {
1241                 row[group_columns.text] = _("unnamed");
1242                 focus = true;
1243         }
1244
1245         group->FlagsChanged.connect (bind (mem_fun(*this, &Mixer_UI::group_flags_changed), group));
1246         
1247         if (focus) {
1248                 TreeViewColumn* col = group_display.get_column (0);
1249                 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
1250                 group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true);
1251         }
1252
1253         in_group_row_change = false;
1254 }
1255
1256 bool
1257 Mixer_UI::strip_scroller_button_release (GdkEventButton* ev)
1258 {
1259         using namespace Menu_Helpers;
1260
1261         if (Keyboard::is_context_menu_event (ev)) {
1262                 ARDOUR_UI::instance()->add_route (this);
1263                 return true;
1264         }
1265
1266         return false;
1267 }
1268
1269 void
1270 Mixer_UI::set_strip_width (Width w)
1271 {
1272         _strip_width = w;
1273
1274         for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1275                 (*i)->set_width (w, this);
1276         }
1277 }
1278
1279 void
1280 Mixer_UI::set_window_pos_and_size ()
1281 {
1282         resize (m_width, m_height);
1283         move (m_root_x, m_root_y);
1284 }
1285
1286         void
1287 Mixer_UI::get_window_pos_and_size ()
1288 {
1289         get_position(m_root_x, m_root_y);
1290         get_size(m_width, m_height);
1291 }
1292
1293 int
1294 Mixer_UI::set_state (const XMLNode& node)
1295 {
1296         const XMLProperty* prop;
1297         XMLNode* geometry;
1298         
1299         if ((geometry = find_named_node (node, "geometry")) == 0) {
1300
1301                 m_width = default_width;
1302                 m_height = default_height;
1303                 m_root_x = 1;
1304                 m_root_y = 1;
1305
1306         } else {
1307
1308                 m_width = atoi(geometry->property("x_size")->value().c_str());
1309                 m_height = atoi(geometry->property("y_size")->value().c_str());
1310                 m_root_x = atoi(geometry->property("x_pos")->value().c_str());
1311                 m_root_y = atoi(geometry->property("y_pos")->value().c_str());
1312         }
1313
1314         set_window_pos_and_size ();
1315
1316         if ((prop = node.property ("narrow-strips"))) {
1317                 if (prop->value() == "yes") {
1318                         set_strip_width (Narrow);
1319                 } else {
1320                         set_strip_width (Wide);
1321                 }
1322         }
1323
1324         if ((prop = node.property ("show-mixer"))) {
1325                 if (prop->value() == "yes") {
1326                        _visible = true;
1327                 }
1328         }
1329
1330         return 0;
1331 }
1332
1333 XMLNode&
1334 Mixer_UI::get_state (void)
1335 {
1336         XMLNode* node = new XMLNode ("Mixer");
1337
1338         if (is_realized()) {
1339                 Glib::RefPtr<Gdk::Window> win = get_window();
1340         
1341                 get_window_pos_and_size ();
1342
1343                 XMLNode* geometry = new XMLNode ("geometry");
1344                 char buf[32];
1345                 snprintf(buf, sizeof(buf), "%d", m_width);
1346                 geometry->add_property(X_("x_size"), string(buf));
1347                 snprintf(buf, sizeof(buf), "%d", m_height);
1348                 geometry->add_property(X_("y_size"), string(buf));
1349                 snprintf(buf, sizeof(buf), "%d", m_root_x);
1350                 geometry->add_property(X_("x_pos"), string(buf));
1351                 snprintf(buf, sizeof(buf), "%d", m_root_y);
1352                 geometry->add_property(X_("y_pos"), string(buf));
1353                 
1354                 // written only for compatibility, they are not used.
1355                 snprintf(buf, sizeof(buf), "%d", 0);
1356                 geometry->add_property(X_("x_off"), string(buf));
1357                 snprintf(buf, sizeof(buf), "%d", 0);
1358                 geometry->add_property(X_("y_off"), string(buf));
1359
1360                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&rhs_pane1)->gobj()));
1361                 geometry->add_property(X_("mixer_rhs_pane1_pos"), string(buf));
1362                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&list_hpane)->gobj()));
1363                 geometry->add_property(X_("mixer_list_hpane_pos"), string(buf));
1364
1365                 node->add_child_nocopy (*geometry);
1366         }
1367
1368         node->add_property ("narrow-strips", _strip_width == Narrow ? "yes" : "no");
1369
1370         node->add_property ("show-mixer", _visible ? "yes" : "no");
1371
1372         return *node;
1373 }
1374
1375
1376 void 
1377 Mixer_UI::pane_allocation_handler (Allocation& alloc, Gtk::Paned* which)
1378 {
1379         int pos;
1380         XMLProperty* prop = 0;
1381         char buf[32];
1382         XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
1383         XMLNode* geometry;
1384         int width, height;
1385         static int32_t done[3] = { 0, 0, 0 };
1386
1387         if ((geometry = find_named_node (*node, "geometry")) == 0) {
1388                 width = default_width;
1389                 height = default_height;
1390         } else {
1391                 width = atoi(geometry->property("x_size")->value());
1392                 height = atoi(geometry->property("y_size")->value());
1393         }
1394
1395         if (which == static_cast<Gtk::Paned*> (&rhs_pane1)) {
1396
1397                 if (done[0]) {
1398                         return;
1399                 }
1400
1401                 if (!geometry || (prop = geometry->property("mixer_rhs_pane1_pos")) == 0) {
1402                         pos = height / 3;
1403                         snprintf (buf, sizeof(buf), "%d", pos);
1404                 } else {
1405                         pos = atoi (prop->value());
1406                 }
1407
1408                 if ((done[0] = GTK_WIDGET(rhs_pane1.gobj())->allocation.height > pos)) {
1409                         rhs_pane1.set_position (pos);
1410                 }
1411
1412         } else if (which == static_cast<Gtk::Paned*> (&list_hpane)) {
1413
1414                 if (done[2]) {
1415                         return;
1416                 }
1417
1418                 if (!geometry || (prop = geometry->property("mixer_list_hpane_pos")) == 0) {
1419                         pos = 75;
1420                         snprintf (buf, sizeof(buf), "%d", pos);
1421                 } else {
1422                         pos = atoi (prop->value());
1423                 }
1424
1425                 if ((done[2] = GTK_WIDGET(list_hpane.gobj())->allocation.width > pos)) {
1426                         list_hpane.set_position (pos);
1427                 }
1428         }
1429 }
1430
1431 bool
1432 Mixer_UI::on_key_press_event (GdkEventKey* ev)
1433 {
1434         return key_press_focus_accelerator_handler (*this, ev);
1435 }