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