update drobilla's fascistic dir-locals.el to force emacs users into whitespace submis...
[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 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 #include <algorithm>
25 #include <map>
26 #include <sigc++/bind.h>
27
28 #include <gtkmm/accelmap.h>
29
30 #include "pbd/convert.h"
31 #include "pbd/stacktrace.h"
32 #include <glibmm/thread.h>
33
34 #include <gtkmm2ext/gtk_ui.h>
35 #include <gtkmm2ext/utils.h>
36 #include <gtkmm2ext/tearoff.h>
37 #include <gtkmm2ext/window_title.h>
38
39 #include "ardour/audio_track.h"
40 #include "ardour/plugin_manager.h"
41 #include "ardour/route_group.h"
42 #include "ardour/session.h"
43 #include "ardour/session_route.h"
44
45 #include "keyboard.h"
46 #include "mixer_ui.h"
47 #include "mixer_strip.h"
48 #include "monitor_section.h"
49 #include "plugin_selector.h"
50 #include "ardour_ui.h"
51 #include "prompter.h"
52 #include "utils.h"
53 #include "actions.h"
54 #include "gui_thread.h"
55 #include "mixer_group_tabs.h"
56
57 #include "i18n.h"
58
59 using namespace ARDOUR;
60 using namespace PBD;
61 using namespace Gtk;
62 using namespace Glib;
63 using namespace Gtkmm2ext;
64 using namespace std;
65
66 using PBD::atoi;
67
68 Mixer_UI::Mixer_UI ()
69         : Window (Gtk::WINDOW_TOPLEVEL)
70 {
71         _strip_width = Config->get_default_narrow_ms() ? Narrow : Wide;
72         track_menu = 0;
73         _monitor_section = 0;
74         no_track_list_redisplay = false;
75         in_group_row_change = false;
76         _visible = false;
77         strip_redisplay_does_not_reset_order_keys = false;
78         strip_redisplay_does_not_sync_order_keys = false;
79         ignore_sync = false;
80
81         Route::SyncOrderKeys.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::sync_order_keys, this, _1), gui_context());
82
83         scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
84         scroller_base.set_name ("MixerWindow");
85         scroller_base.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::strip_scroller_button_release));
86         // add as last item of strip packer
87         strip_packer.pack_end (scroller_base, true, true);
88
89         _group_tabs = new MixerGroupTabs (this);
90         VBox* b = manage (new VBox);
91         b->pack_start (*_group_tabs, PACK_SHRINK);
92         b->pack_start (strip_packer);
93         b->show_all ();
94
95         scroller.add (*b);
96         scroller.set_policy (Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
97
98         setup_track_display ();
99
100         group_model = ListStore::create (group_columns);
101         group_display.set_model (group_model);
102         group_display.append_column (_("Group"), group_columns.text);
103         group_display.append_column (_("Show"), group_columns.visible);
104         group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
105         group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
106         group_display.get_column (0)->set_expand(true);
107         group_display.get_column (1)->set_expand(false);
108         group_display.set_name ("MixerGroupList");
109         group_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
110         group_display.set_reorderable (true);
111         group_display.set_headers_visible (true);
112         group_display.set_rules_hint (true);
113
114         /* name is directly editable */
115
116         CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
117         name_cell->property_editable() = true;
118         name_cell->signal_edited().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_name_edit));
119
120         /* use checkbox for the active column */
121
122         CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(group_display.get_column_cell_renderer (1));
123         active_cell->property_activatable() = true;
124         active_cell->property_radio() = false;
125
126         group_model->signal_row_changed().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_change));
127
128         group_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::group_display_button_press), false);
129
130         group_display_scroller.add (group_display);
131         group_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
132
133         HBox* route_group_display_button_box = manage (new HBox());
134
135         Button* route_group_add_button = manage (new Button ());
136         Button* route_group_remove_button = manage (new Button ());
137
138         Widget* w;
139
140         w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
141         w->show();
142         route_group_add_button->add (*w);
143
144         w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
145         w->show();
146         route_group_remove_button->add (*w);
147
148         route_group_display_button_box->set_homogeneous (true);
149
150         route_group_add_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_route_group));
151         route_group_remove_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::remove_selected_route_group));
152
153         route_group_display_button_box->add (*route_group_add_button);
154         route_group_display_button_box->add (*route_group_remove_button);
155
156         group_display_vbox.pack_start (group_display_scroller, true, true);
157         group_display_vbox.pack_start (*route_group_display_button_box, false, false);
158
159         group_display_frame.set_name ("BaseFrame");
160         group_display_frame.set_shadow_type (Gtk::SHADOW_IN);
161         group_display_frame.add (group_display_vbox);
162
163         rhs_pane1.pack1 (track_display_frame);
164         rhs_pane1.pack2 (group_display_frame);
165
166         list_vpacker.pack_start (rhs_pane1, true, true);
167
168         global_hpacker.pack_start (scroller, true, true);
169 #ifdef GTKOSX
170         /* current gtk-quartz has dirty updates on borders like this one */
171         global_hpacker.pack_start (out_packer, false, false, 0);
172 #else
173         global_hpacker.pack_start (out_packer, false, false, 12);
174 #endif
175         list_hpane.add1(list_vpacker);
176         list_hpane.add2(global_hpacker);
177
178         rhs_pane1.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
179                                                         static_cast<Gtk::Paned*> (&rhs_pane1)));
180         list_hpane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
181                                                          static_cast<Gtk::Paned*> (&list_hpane)));
182
183         global_vpacker.pack_start (list_hpane, true, true);
184
185         add (global_vpacker);
186         set_name ("MixerWindow");
187
188         WindowTitle title(Glib::get_application_name());
189         title += _("Mixer");
190         set_title (title.get_string());
191
192         set_wmclass (X_("ardour_mixer"), PROGRAM_NAME);
193
194         add_accel_group (ActionManager::ui_manager->get_accel_group());
195
196         signal_delete_event().connect (sigc::mem_fun (*this, &Mixer_UI::hide_window));
197         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
198
199         signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
200
201         _selection.RoutesChanged.connect (sigc::mem_fun(*this, &Mixer_UI::follow_strip_selection));
202
203         route_group_display_button_box->show();
204         route_group_add_button->show();
205         route_group_remove_button->show();
206
207         global_hpacker.show();
208         global_vpacker.show();
209         scroller.show();
210         scroller_base.show();
211         scroller_hpacker.show();
212         mixer_scroller_vpacker.show();
213         list_vpacker.show();
214         group_display_button_label.show();
215         group_display_button.show();
216         group_display_scroller.show();
217         group_display_vbox.show();
218         group_display_frame.show();
219         rhs_pane1.show();
220         strip_packer.show();
221         out_packer.show();
222         list_hpane.show();
223         group_display.show();
224
225         auto_rebinding = FALSE;
226
227         MixerStrip::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::remove_strip, this, _1), gui_context());
228
229         MonitorSection::setup_knob_images ();
230
231 #ifndef DEFER_PLUGIN_SELECTOR_LOAD
232         _plugin_selector = new PluginSelector (PluginManager::the_manager ());
233 #endif
234 }
235
236 Mixer_UI::~Mixer_UI ()
237 {
238 }
239
240 void
241 Mixer_UI::ensure_float (Window& win)
242 {
243         win.set_transient_for (*this);
244 }
245
246 void
247 Mixer_UI::show_window ()
248 {
249         present ();
250         if (!_visible) {
251                 set_window_pos_and_size ();
252
253                 /* show/hide group tabs as required */
254                 parameter_changed ("show-group-tabs");
255
256                 /* now reset each strips width so the right widgets are shown */
257                 MixerStrip* ms;
258
259                 TreeModel::Children rows = track_model->children();
260                 TreeModel::Children::iterator ri;
261
262                 for (ri = rows.begin(); ri != rows.end(); ++ri) {
263                         ms = (*ri)[track_columns.strip];
264                         ms->set_width_enum (ms->get_width_enum (), ms->width_owner());
265                 }
266         }
267         _visible = true;
268 }
269
270 bool
271 Mixer_UI::hide_window (GdkEventAny *ev)
272 {
273         get_window_pos_and_size ();
274
275         _visible = false;
276         return just_hide_it(ev, static_cast<Gtk::Window *>(this));
277 }
278
279
280 void
281 Mixer_UI::add_strip (RouteList& routes)
282 {
283         ENSURE_GUI_THREAD (*this, &Mixer_UI::add_strip, routes)
284
285         MixerStrip* strip;
286
287         no_track_list_redisplay = true;
288         strip_redisplay_does_not_sync_order_keys = true;
289
290         for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
291                 boost::shared_ptr<Route> route = (*x);
292
293                 if (route->is_hidden()) {
294                         continue;
295                 }
296
297                 if (route->is_monitor()) {
298                         if (!_monitor_section) {
299                                 _monitor_section = new MonitorSection (_session);
300                                 out_packer.pack_end (_monitor_section->tearoff(), false, false);
301                         } else {
302                                 _monitor_section->set_session (_session);
303                         }
304
305                         _monitor_section->tearoff().show_all ();
306
307                         XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
308                         if (mnode) {
309                                 _monitor_section->tearoff().set_state (*mnode);
310                         }
311
312                         /* no regular strip shown for control out */
313
314                         continue;
315                 }
316
317                 strip = new MixerStrip (*this, _session, route);
318                 strips.push_back (strip);
319
320                 Config->get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide;
321
322                 if (strip->width_owner() != strip) {
323                         strip->set_width_enum (_strip_width, this);
324                 }
325
326                 show_strip (strip);
327
328                 TreeModel::Row row = *(track_model->append());
329                 row[track_columns.text] = route->name();
330                 row[track_columns.visible] = strip->marked_for_display();
331                 row[track_columns.route] = route;
332                 row[track_columns.strip] = strip;
333
334                 if (route->order_key (N_("signal")) == -1) {
335                         route->set_order_key (N_("signal"), track_model->children().size()-1);
336                 }
337
338                 route->PropertyChanged.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::strip_property_changed, this, _1, strip), gui_context());
339
340                 strip->WidthChanged.connect (sigc::mem_fun(*this, &Mixer_UI::strip_width_changed));
341                 strip->signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::strip_button_release_event), strip));
342         }
343
344         no_track_list_redisplay = false;
345
346         redisplay_track_list ();
347
348         strip_redisplay_does_not_sync_order_keys = false;
349 }
350
351 void
352 Mixer_UI::remove_strip (MixerStrip* strip)
353 {
354         if (_session && _session->deletion_in_progress()) {
355                 /* its all being taken care of */
356                 return;
357         }
358
359         ENSURE_GUI_THREAD (*this, &Mixer_UI::remove_strip, strip);
360
361         cerr << "Mixer UI removing strip for " << strip << endl;
362
363         TreeModel::Children rows = track_model->children();
364         TreeModel::Children::iterator ri;
365         list<MixerStrip *>::iterator i;
366
367         if ((i = find (strips.begin(), strips.end(), strip)) != strips.end()) {
368                 strips.erase (i);
369         }
370
371         strip_redisplay_does_not_sync_order_keys = true;
372
373         for (ri = rows.begin(); ri != rows.end(); ++ri) {
374                 if ((*ri)[track_columns.strip] == strip) {
375                         track_model->erase (ri);
376                         break;
377                 }
378         }
379
380         strip_redisplay_does_not_sync_order_keys = false;
381 }
382
383 void
384 Mixer_UI::sync_order_keys (string const & src)
385 {
386         TreeModel::Children rows = track_model->children();
387         TreeModel::Children::iterator ri;
388
389         if (src == N_("signal") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
390                 return;
391         }
392
393         std::map<int,int> keys;
394
395         bool changed = false;
396
397         unsigned order = 0;
398         for (ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
399                 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
400                 unsigned int old_key = order;
401                 unsigned int new_key = route->order_key (N_("signal"));
402
403                 keys[new_key] = old_key;
404
405                 if (new_key != old_key) {
406                         changed = true;
407                 }
408         }
409
410         if (keys.size() != rows.size()) {
411                 PBD::stacktrace (cerr, 20);
412         }
413         assert(keys.size() == rows.size());
414
415         // Remove any gaps in keys caused by automation children tracks
416         vector<int> neworder;
417         for (std::map<int,int>::const_iterator i = keys.begin(); i != keys.end(); ++i) {
418                 neworder.push_back(i->second);
419         }
420         assert(neworder.size() == rows.size());
421
422         if (changed) {
423                 strip_redisplay_does_not_reset_order_keys = true;
424                 track_model->reorder (neworder);
425                 strip_redisplay_does_not_reset_order_keys = false;
426         }
427 }
428
429 void
430 Mixer_UI::follow_strip_selection ()
431 {
432         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
433                 (*i)->set_selected (_selection.selected ((*i)->route()));
434         }
435 }
436
437 bool
438 Mixer_UI::strip_button_release_event (GdkEventButton *ev, MixerStrip *strip)
439 {
440         if (ev->button == 1) {
441
442                 /* this allows the user to click on the strip to terminate comment
443                    editing. XXX it needs improving so that we don't select the strip
444                    at the same time.
445                 */
446
447                 if (_selection.selected (strip->route())) {
448                         _selection.remove (strip->route());
449                 } else {
450                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
451                                 _selection.add (strip->route());
452                         } else {
453                                 _selection.set (strip->route());
454                         }
455                 }
456         }
457
458         return true;
459 }
460
461 void
462 Mixer_UI::set_session (Session* sess)
463 {
464         SessionHandlePtr::set_session (sess);
465
466         if (_plugin_selector) {
467                 _plugin_selector->set_session (_session);
468         }
469
470         _group_tabs->set_session (sess);
471
472         if (!_session) {
473                 return;
474         }
475
476         XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
477         set_state (*node);
478
479         WindowTitle title(_session->name());
480         title += _("Mixer");
481         title += Glib::get_application_name();
482
483         set_title (title.get_string());
484
485         initial_track_display ();
486
487         _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Mixer_UI::add_strip, this, _1), gui_context());
488         _session->route_group_added.connect (_session_connections, invalidator (*this), ui_bind (&Mixer_UI::add_route_group, this, _1), gui_context());
489         _session->route_group_removed.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
490         _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Mixer_UI::parameter_changed, this, _1), gui_context());
491
492         Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::parameter_changed, this, _1), gui_context ());
493
494         route_groups_changed ();
495
496         if (_visible) {
497                 show_window();
498         }
499
500         start_updating ();
501 }
502
503 void
504 Mixer_UI::session_going_away ()
505 {
506         ENSURE_GUI_THREAD (*this, &Mixer_UI::session_going_away)
507
508         group_model->clear ();
509         _selection.clear ();
510         track_model->clear ();
511
512         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
513                 delete (*i);
514         }
515
516         if (_monitor_section) {
517                 _monitor_section->tearoff().hide_visible ();
518         }
519
520         strips.clear ();
521
522         WindowTitle title(Glib::get_application_name());
523         title += _("Mixer");
524         set_title (title.get_string());
525
526         stop_updating ();
527
528         SessionHandlePtr::session_going_away ();
529 }
530
531 void
532 Mixer_UI::show_strip (MixerStrip* ms)
533 {
534         TreeModel::Children rows = track_model->children();
535         TreeModel::Children::iterator i;
536
537         for (i = rows.begin(); i != rows.end(); ++i) {
538
539                 MixerStrip* strip = (*i)[track_columns.strip];
540                 if (strip == ms) {
541                         (*i)[track_columns.visible] = true;
542                         break;
543                 }
544         }
545 }
546
547 void
548 Mixer_UI::hide_strip (MixerStrip* ms)
549 {
550         TreeModel::Children rows = track_model->children();
551         TreeModel::Children::iterator i;
552
553         for (i = rows.begin(); i != rows.end(); ++i) {
554
555                 MixerStrip* strip = (*i)[track_columns.strip];
556                 if (strip == ms) {
557                         (*i)[track_columns.visible] = false;
558                         break;
559                 }
560         }
561 }
562
563 gint
564 Mixer_UI::start_updating ()
565 {
566     fast_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &Mixer_UI::fast_update_strips));
567     return 0;
568 }
569
570 gint
571 Mixer_UI::stop_updating ()
572 {
573     fast_screen_update_connection.disconnect();
574     return 0;
575 }
576
577 void
578 Mixer_UI::fast_update_strips ()
579 {
580         if (is_mapped () && _session) {
581                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
582                         (*i)->fast_update ();
583                 }
584         }
585 }
586
587 void
588 Mixer_UI::set_all_strips_visibility (bool yn)
589 {
590         TreeModel::Children rows = track_model->children();
591         TreeModel::Children::iterator i;
592
593         no_track_list_redisplay = true;
594
595         for (i = rows.begin(); i != rows.end(); ++i) {
596
597                 TreeModel::Row row = (*i);
598                 MixerStrip* strip = row[track_columns.strip];
599
600                 if (strip == 0) {
601                         continue;
602                 }
603
604                 if (strip->route()->is_master() || strip->route()->is_monitor()) {
605                         continue;
606                 }
607
608                 (*i)[track_columns.visible] = yn;
609         }
610
611         no_track_list_redisplay = false;
612         redisplay_track_list ();
613 }
614
615
616 void
617 Mixer_UI::set_all_audio_visibility (int tracks, bool yn)
618 {
619         TreeModel::Children rows = track_model->children();
620         TreeModel::Children::iterator i;
621
622         no_track_list_redisplay = true;
623
624         for (i = rows.begin(); i != rows.end(); ++i) {
625                 TreeModel::Row row = (*i);
626                 MixerStrip* strip = row[track_columns.strip];
627
628                 if (strip == 0) {
629                         continue;
630                 }
631
632                 if (strip->route()->is_master() || strip->route()->is_monitor()) {
633                         continue;
634                 }
635
636                 boost::shared_ptr<AudioTrack> at = strip->audio_track();
637
638                 switch (tracks) {
639                 case 0:
640                         (*i)[track_columns.visible] = yn;
641                         break;
642
643                 case 1:
644                         if (at) { /* track */
645                                 (*i)[track_columns.visible] = yn;
646                         }
647                         break;
648
649                 case 2:
650                         if (!at) { /* bus */
651                                 (*i)[track_columns.visible] = yn;
652                         }
653                         break;
654                 }
655         }
656
657         no_track_list_redisplay = false;
658         redisplay_track_list ();
659 }
660
661 void
662 Mixer_UI::hide_all_routes ()
663 {
664         set_all_strips_visibility (false);
665 }
666
667 void
668 Mixer_UI::show_all_routes ()
669 {
670         set_all_strips_visibility (true);
671 }
672
673 void
674 Mixer_UI::show_all_audiobus ()
675 {
676         set_all_audio_visibility (2, true);
677 }
678 void
679 Mixer_UI::hide_all_audiobus ()
680 {
681         set_all_audio_visibility (2, false);
682 }
683
684 void
685 Mixer_UI::show_all_audiotracks()
686 {
687         set_all_audio_visibility (1, true);
688 }
689 void
690 Mixer_UI::hide_all_audiotracks ()
691 {
692         set_all_audio_visibility (1, false);
693 }
694
695 void
696 Mixer_UI::track_list_reorder (const TreeModel::Path&, const TreeModel::iterator&, int* /*new_order*/)
697 {
698         strip_redisplay_does_not_sync_order_keys = true;
699         _session->set_remote_control_ids();
700         redisplay_track_list ();
701         strip_redisplay_does_not_sync_order_keys = false;
702 }
703
704 void
705 Mixer_UI::track_list_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator&)
706 {
707         // never reset order keys because of a property change
708         strip_redisplay_does_not_reset_order_keys = true;
709         _session->set_remote_control_ids();
710         redisplay_track_list ();
711         strip_redisplay_does_not_reset_order_keys = false;
712 }
713
714 void
715 Mixer_UI::track_list_delete (const Gtk::TreeModel::Path&)
716 {
717         /* this could require an order sync */
718         if (_session && !_session->deletion_in_progress()) {
719                 _session->set_remote_control_ids();
720                 redisplay_track_list ();
721         }
722 }
723
724 void
725 Mixer_UI::redisplay_track_list ()
726 {
727         TreeModel::Children rows = track_model->children();
728         TreeModel::Children::iterator i;
729         long order;
730
731         if (no_track_list_redisplay) {
732                 return;
733         }
734
735         for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
736                 MixerStrip* strip = (*i)[track_columns.strip];
737
738                 if (strip == 0) {
739                         /* we're in the middle of changing a row, don't worry */
740                         continue;
741                 }
742
743                 bool visible = (*i)[track_columns.visible];
744
745                 if (visible) {
746                         strip->set_marked_for_display (true);
747                         strip->route()->set_order_key (N_("signal"), order);
748
749                         if (!strip_redisplay_does_not_reset_order_keys) {
750                                 strip->route()->set_order_key (N_("signal"), order);
751                         }
752
753                         if (strip->packed()) {
754
755                                 if (strip->route()->is_master() || strip->route()->is_monitor()) {
756                                         out_packer.reorder_child (*strip, -1);
757                                 } else {
758                                         strip_packer.reorder_child (*strip, -1); /* put at end */
759                                 }
760
761                         } else {
762
763                                 if (strip->route()->is_master() || strip->route()->is_monitor()) {
764                                         out_packer.pack_start (*strip, false, false);
765                                 } else {
766                                         strip_packer.pack_start (*strip, false, false);
767                                 }
768                                 strip->set_packed (true);
769                                 //strip->show();
770                         }
771
772                 } else {
773
774                         strip->set_marked_for_display (false);
775
776                         if (strip->route()->is_master() || strip->route()->is_monitor()) {
777                                 /* do nothing, these cannot be hidden */
778                         } else {
779                                 if (strip->packed()) {
780                                         strip_packer.remove (*strip);
781                                         strip->set_packed (false);
782                                 }
783                         }
784                 }
785         }
786
787         if (!strip_redisplay_does_not_reset_order_keys && !strip_redisplay_does_not_sync_order_keys) {
788                 _session->sync_order_keys (N_("signal"));
789         }
790
791         // Resigc::bind all of the midi controls automatically
792
793         if (auto_rebinding)
794                 auto_rebind_midi_controls ();
795
796         _group_tabs->set_dirty ();
797 }
798
799 void
800 Mixer_UI::strip_width_changed ()
801 {
802         _group_tabs->set_dirty ();
803
804 #ifdef GTKOSX
805         TreeModel::Children rows = track_model->children();
806         TreeModel::Children::iterator i;
807         long order;
808
809         for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
810                 MixerStrip* strip = (*i)[track_columns.strip];
811
812                 if (strip == 0) {
813                         continue;
814                 }
815
816                 bool visible = (*i)[track_columns.visible];
817
818                 if (visible) {
819                         strip->queue_draw();
820                 }
821         }
822 #endif
823
824 }
825
826 void
827 Mixer_UI::set_auto_rebinding( bool val )
828 {
829         if( val == TRUE )
830         {
831                 auto_rebinding = TRUE;
832                 Session::AutoBindingOff();
833         }
834         else
835         {
836                 auto_rebinding = FALSE;
837                 Session::AutoBindingOn();
838         }
839 }
840
841 void
842 Mixer_UI::toggle_auto_rebinding()
843 {
844         if (auto_rebinding)
845         {
846                 set_auto_rebinding( FALSE );
847         }
848
849         else
850         {
851                 set_auto_rebinding( TRUE );
852         }
853
854         auto_rebind_midi_controls();
855 }
856
857 void
858 Mixer_UI::auto_rebind_midi_controls ()
859 {
860         TreeModel::Children rows = track_model->children();
861         TreeModel::Children::iterator i;
862         int pos;
863
864         // Create bindings for all visible strips and remove those that are not visible
865         pos = 1;  // 0 is reserved for the master strip
866         for (i = rows.begin(); i != rows.end(); ++i) {
867                 MixerStrip* strip = (*i)[track_columns.strip];
868
869                 if ( (*i)[track_columns.visible] == true ) {  // add bindings for
870                         // make the actual binding
871                         //cout<<"Auto Binding:  Visible Strip Found: "<<strip->name()<<endl;
872
873                         int controlValue = pos;
874                         if( strip->route()->is_master() ) {
875                                 controlValue = 0;
876                         }
877                         else {
878                                 pos++;
879                         }
880
881                         PBD::Controllable::CreateBinding ( strip->solo_button->get_controllable().get(), controlValue, 0);
882                         PBD::Controllable::CreateBinding ( strip->mute_button->get_controllable().get(), controlValue, 1);
883
884                         if( strip->is_audio_track() ) {
885                                 PBD::Controllable::CreateBinding ( strip->rec_enable_button->get_controllable().get(), controlValue, 2);
886                         }
887
888                         PBD::Controllable::CreateBinding ( strip->gpm.get_controllable().get(), controlValue, 3);
889                         PBD::Controllable::CreateBinding ( strip->panners.get_controllable().get(), controlValue, 4);
890
891                 }
892                 else {  // Remove any existing binding
893                         PBD::Controllable::DeleteBinding ( strip->solo_button->get_controllable().get() );
894                         PBD::Controllable::DeleteBinding ( strip->mute_button->get_controllable().get() );
895
896                         if( strip->is_audio_track() ) {
897                                 PBD::Controllable::DeleteBinding ( strip->rec_enable_button->get_controllable().get() );
898                         }
899
900                         PBD::Controllable::DeleteBinding ( strip->gpm.get_controllable().get() );
901                         PBD::Controllable::DeleteBinding ( strip->panners.get_controllable().get() ); // This only takes the first panner if there are multiples...
902                 }
903
904         } // for
905
906 }
907
908 struct SignalOrderRouteSorter {
909     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
910             /* use of ">" forces the correct sort order */
911             return a->order_key (N_("signal")) < b->order_key (N_("signal"));
912     }
913 };
914
915 void
916 Mixer_UI::initial_track_display ()
917 {
918         boost::shared_ptr<RouteList> routes = _session->get_routes();
919         RouteList copy (*routes);
920         SignalOrderRouteSorter sorter;
921
922         copy.sort (sorter);
923
924         no_track_list_redisplay = true;
925
926         track_model->clear ();
927
928         add_strip (copy);
929
930         no_track_list_redisplay = false;
931
932         redisplay_track_list ();
933 }
934
935 void
936 Mixer_UI::show_track_list_menu ()
937 {
938         if (track_menu == 0) {
939                 build_track_menu ();
940         }
941
942         track_menu->popup (1, gtk_get_current_event_time());
943 }
944
945 bool
946 Mixer_UI::track_display_button_press (GdkEventButton* ev)
947 {
948         if (Keyboard::is_context_menu_event (ev)) {
949                 show_track_list_menu ();
950                 return true;
951         }
952
953         TreeIter iter;
954         TreeModel::Path path;
955         TreeViewColumn* column;
956         int cellx;
957         int celly;
958
959         if (!track_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
960                 return false;
961         }
962
963         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
964         case 0:
965                 /* allow normal processing to occur */
966                 return false;
967
968         case 1: /* visibility */
969
970                 if ((iter = track_model->get_iter (path))) {
971                         MixerStrip* strip = (*iter)[track_columns.strip];
972                         if (strip) {
973
974                                 if (!strip->route()->is_master() && !strip->route()->is_monitor()) {
975                                         bool visible = (*iter)[track_columns.visible];
976                                         (*iter)[track_columns.visible] = !visible;
977                                 }
978 #ifdef GTKOSX
979                                 track_display.queue_draw();
980 #endif
981                         }
982                 }
983                 return true;
984
985         default:
986                 break;
987         }
988
989         return false;
990 }
991
992
993 void
994 Mixer_UI::build_track_menu ()
995 {
996         using namespace Menu_Helpers;
997         using namespace Gtk;
998
999         track_menu = new Menu;
1000         track_menu->set_name ("ArdourContextMenu");
1001         MenuList& items = track_menu->items();
1002
1003         items.push_back (MenuElem (_("Show All"), sigc::mem_fun(*this, &Mixer_UI::show_all_routes)));
1004         items.push_back (MenuElem (_("Hide All"), sigc::mem_fun(*this, &Mixer_UI::hide_all_routes)));
1005         items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
1006         items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
1007         items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus)));
1008         items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
1009
1010 }
1011
1012 void
1013 Mixer_UI::strip_property_changed (const PropertyChange& what_changed, MixerStrip* mx)
1014 {
1015         if (!what_changed.contains (ARDOUR::Properties::name)) {
1016                 return;
1017         }
1018
1019         ENSURE_GUI_THREAD (*this, &Mixer_UI::strip_name_changed, what_changed, mx)
1020
1021         TreeModel::Children rows = track_model->children();
1022         TreeModel::Children::iterator i;
1023
1024         for (i = rows.begin(); i != rows.end(); ++i) {
1025                 if ((*i)[track_columns.strip] == mx) {
1026                         (*i)[track_columns.text] = mx->route()->name();
1027                         return;
1028                 }
1029         }
1030
1031         error << _("track display list item for renamed strip not found!") << endmsg;
1032 }
1033
1034 bool
1035 Mixer_UI::group_display_button_press (GdkEventButton* ev)
1036 {
1037         TreeModel::Path path;
1038         TreeViewColumn* column;
1039         int cellx;
1040         int celly;
1041
1042         if (!group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
1043                 return false;
1044         }
1045
1046         TreeIter iter = group_model->get_iter (path);
1047         if (!iter) {
1048                 return false;
1049         }
1050
1051         RouteGroup* group = (*iter)[group_columns.group];
1052
1053         if (Keyboard::is_context_menu_event (ev)) {
1054                 _group_tabs->get_menu(group)->popup (1, ev->time);
1055                 return true;
1056         }
1057
1058         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
1059         case 0:
1060                 if (Keyboard::is_edit_event (ev)) {
1061                         if (group) {
1062                                 // edit_route_group (group);
1063 #ifdef GTKOSX
1064                                 group_display.queue_draw();
1065 #endif
1066                                 return true;
1067                         }
1068                 }
1069                 break;
1070
1071         case 1:
1072         {
1073                 bool visible = (*iter)[group_columns.visible];
1074                 (*iter)[group_columns.visible] = !visible;
1075 #ifdef GTKOSX
1076                 group_display.queue_draw();
1077 #endif
1078                 return true;
1079         }
1080
1081         default:
1082                 break;
1083         }
1084
1085         return false;
1086  }
1087
1088 void
1089 Mixer_UI::activate_all_route_groups ()
1090 {
1091         _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), true));
1092 }
1093
1094 void
1095 Mixer_UI::disable_all_route_groups ()
1096 {
1097         _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), false));
1098 }
1099
1100 void
1101 Mixer_UI::route_groups_changed ()
1102 {
1103         ENSURE_GUI_THREAD (*this, &Mixer_UI::route_groups_changed)
1104
1105         /* just rebuild the while thing */
1106
1107         group_model->clear ();
1108
1109         {
1110                 TreeModel::Row row;
1111                 row = *(group_model->append());
1112                 row[group_columns.visible] = true;
1113                 row[group_columns.text] = (_("-all-"));
1114                 row[group_columns.group] = 0;
1115         }
1116
1117         _session->foreach_route_group (sigc::mem_fun (*this, &Mixer_UI::add_route_group));
1118
1119         _group_tabs->set_dirty ();
1120 }
1121
1122 void
1123 Mixer_UI::new_route_group ()
1124 {
1125         RouteList rl;
1126         
1127         _group_tabs->run_new_group_dialog (rl);
1128 }
1129
1130 void
1131 Mixer_UI::remove_selected_route_group ()
1132 {
1133         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1134         TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1135
1136         if (rows.empty()) {
1137                 return;
1138         }
1139
1140         TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1141         TreeIter iter;
1142
1143         /* selection mode is single, so rows.begin() is it */
1144
1145         if ((iter = group_model->get_iter (*i))) {
1146
1147                 RouteGroup* rg = (*iter)[group_columns.group];
1148
1149                 if (rg) {
1150                         _session->remove_route_group (*rg);
1151                 }
1152         }
1153 }
1154
1155 void
1156 Mixer_UI::route_group_property_changed (RouteGroup* group, const PropertyChange& change)
1157 {
1158         if (in_group_row_change) {
1159                 return;
1160         }
1161
1162         /* force an update of any mixer strips that are using this group,
1163            otherwise mix group names don't change in mixer strips
1164         */
1165
1166         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1167                 if ((*i)->route_group() == group) {
1168                         (*i)->route_group_changed();
1169                 }
1170         }
1171
1172         TreeModel::iterator i;
1173         TreeModel::Children rows = group_model->children();
1174         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1175
1176         in_group_row_change = true;
1177
1178         for (i = rows.begin(); i != rows.end(); ++i) {
1179                 if ((*i)[group_columns.group] == group) {
1180                         (*i)[group_columns.visible] = !group->is_hidden ();
1181                         (*i)[group_columns.text] = group->name ();
1182                         break;
1183                 }
1184         }
1185
1186         in_group_row_change = false;
1187
1188         if (change.contains (Properties::name)) {
1189                 _group_tabs->set_dirty ();
1190         }
1191 }
1192
1193 void
1194 Mixer_UI::route_group_name_edit (const std::string& path, const std::string& new_text)
1195 {
1196         RouteGroup* group;
1197         TreeIter iter;
1198
1199         if ((iter = group_model->get_iter (path))) {
1200
1201                 if ((group = (*iter)[group_columns.group]) == 0) {
1202                         return;
1203                 }
1204
1205                 if (new_text != group->name()) {
1206                         group->set_name (new_text);
1207                 }
1208         }
1209 }
1210
1211 void
1212 Mixer_UI::route_group_row_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator& iter)
1213 {
1214         RouteGroup* group;
1215
1216         if (in_group_row_change) {
1217                 return;
1218         }
1219
1220         if ((group = (*iter)[group_columns.group]) == 0) {
1221                 return;
1222         }
1223
1224         if ((*iter)[group_columns.visible]) {
1225                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1226                         if ((*i)->route_group() == group) {
1227                                 show_strip (*i);
1228                         }
1229                 }
1230         } else {
1231                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1232                         if ((*i)->route_group() == group) {
1233                                 hide_strip (*i);
1234                         }
1235                 }
1236         }
1237
1238         std::string name = (*iter)[group_columns.text];
1239
1240         if (name != group->name()) {
1241                 group->set_name (name);
1242         }
1243
1244 }
1245
1246 void
1247 Mixer_UI::add_route_group (RouteGroup* group)
1248 {
1249         ENSURE_GUI_THREAD (*this, &Mixer_UI::add_route_group, group)
1250         bool focus = false;
1251
1252         in_group_row_change = true;
1253
1254         TreeModel::Row row = *(group_model->append());
1255         row[group_columns.visible] = true;
1256         row[group_columns.group] = group;
1257         if (!group->name().empty()) {
1258                 row[group_columns.text] = group->name();
1259         } else {
1260                 row[group_columns.text] = _("unnamed");
1261                 focus = true;
1262         }
1263
1264         group->PropertyChanged.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::route_group_property_changed, this, group, _1), gui_context());
1265
1266         if (focus) {
1267                 TreeViewColumn* col = group_display.get_column (0);
1268                 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
1269                 group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true);
1270         }
1271
1272         _group_tabs->set_dirty ();
1273
1274         in_group_row_change = false;
1275 }
1276
1277 bool
1278 Mixer_UI::strip_scroller_button_release (GdkEventButton* ev)
1279 {
1280         using namespace Menu_Helpers;
1281
1282         if (Keyboard::is_context_menu_event (ev)) {
1283                 ARDOUR_UI::instance()->add_route (this);
1284                 return true;
1285         }
1286
1287         return false;
1288 }
1289
1290 void
1291 Mixer_UI::set_strip_width (Width w)
1292 {
1293         _strip_width = w;
1294
1295         for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1296                 (*i)->set_width_enum (w, this);
1297         }
1298 }
1299
1300 void
1301 Mixer_UI::set_window_pos_and_size ()
1302 {
1303         resize (m_width, m_height);
1304         move (m_root_x, m_root_y);
1305 }
1306
1307         void
1308 Mixer_UI::get_window_pos_and_size ()
1309 {
1310         get_position(m_root_x, m_root_y);
1311         get_size(m_width, m_height);
1312 }
1313
1314 int
1315 Mixer_UI::set_state (const XMLNode& node)
1316 {
1317         const XMLProperty* prop;
1318         XMLNode* geometry;
1319
1320         m_width = default_width;
1321         m_height = default_height;
1322         m_root_x = 1;
1323         m_root_y = 1;
1324
1325         if ((geometry = find_named_node (node, "geometry")) != 0) {
1326
1327                 XMLProperty* prop;
1328
1329                 if ((prop = geometry->property("x_size")) == 0) {
1330                         prop = geometry->property ("x-size");
1331                 }
1332                 if (prop) {
1333                         m_width = atoi(prop->value());
1334                 }
1335                 if ((prop = geometry->property("y_size")) == 0) {
1336                         prop = geometry->property ("y-size");
1337                 }
1338                 if (prop) {
1339                         m_height = atoi(prop->value());
1340                 }
1341
1342                 if ((prop = geometry->property ("x_pos")) == 0) {
1343                         prop = geometry->property ("x-pos");
1344                 }
1345                 if (prop) {
1346                         m_root_x = atoi (prop->value());
1347
1348                 }
1349                 if ((prop = geometry->property ("y_pos")) == 0) {
1350                         prop = geometry->property ("y-pos");
1351                 }
1352                 if (prop) {
1353                         m_root_y = atoi (prop->value());
1354                 }
1355         }
1356
1357         set_window_pos_and_size ();
1358
1359         if ((prop = node.property ("narrow-strips"))) {
1360                 if (string_is_affirmative (prop->value())) {
1361                         set_strip_width (Narrow);
1362                 } else {
1363                         set_strip_width (Wide);
1364                 }
1365         }
1366
1367         if ((prop = node.property ("show-mixer"))) {
1368                 if (string_is_affirmative (prop->value())) {
1369                        _visible = true;
1370                 }
1371         }
1372
1373         return 0;
1374 }
1375
1376 XMLNode&
1377 Mixer_UI::get_state (void)
1378 {
1379         XMLNode* node = new XMLNode ("Mixer");
1380
1381         if (is_realized()) {
1382                 Glib::RefPtr<Gdk::Window> win = get_window();
1383
1384                 get_window_pos_and_size ();
1385
1386                 XMLNode* geometry = new XMLNode ("geometry");
1387                 char buf[32];
1388                 snprintf(buf, sizeof(buf), "%d", m_width);
1389                 geometry->add_property(X_("x_size"), string(buf));
1390                 snprintf(buf, sizeof(buf), "%d", m_height);
1391                 geometry->add_property(X_("y_size"), string(buf));
1392                 snprintf(buf, sizeof(buf), "%d", m_root_x);
1393                 geometry->add_property(X_("x_pos"), string(buf));
1394                 snprintf(buf, sizeof(buf), "%d", m_root_y);
1395                 geometry->add_property(X_("y_pos"), string(buf));
1396
1397                 // written only for compatibility, they are not used.
1398                 snprintf(buf, sizeof(buf), "%d", 0);
1399                 geometry->add_property(X_("x_off"), string(buf));
1400                 snprintf(buf, sizeof(buf), "%d", 0);
1401                 geometry->add_property(X_("y_off"), string(buf));
1402
1403                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&rhs_pane1)->gobj()));
1404                 geometry->add_property(X_("mixer_rhs_pane1_pos"), string(buf));
1405                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&list_hpane)->gobj()));
1406                 geometry->add_property(X_("mixer_list_hpane_pos"), string(buf));
1407
1408                 node->add_child_nocopy (*geometry);
1409         }
1410
1411         node->add_property ("narrow-strips", _strip_width == Narrow ? "yes" : "no");
1412
1413         node->add_property ("show-mixer", _visible ? "yes" : "no");
1414
1415         return *node;
1416 }
1417
1418
1419 void
1420 Mixer_UI::pane_allocation_handler (Allocation&, Gtk::Paned* which)
1421 {
1422         int pos;
1423         XMLProperty* prop = 0;
1424         char buf[32];
1425         XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
1426         XMLNode* geometry;
1427         int width, height;
1428         static int32_t done[3] = { 0, 0, 0 };
1429
1430         width = default_width;
1431         height = default_height;
1432
1433         if ((geometry = find_named_node (*node, "geometry")) != 0) {
1434
1435
1436                 if ((prop = geometry->property ("x_size")) == 0) {
1437                         prop = geometry->property ("x-size");
1438                 }
1439                 if (prop) {
1440                         width = atoi (prop->value());
1441                 }
1442                 if ((prop = geometry->property ("y_size")) == 0) {
1443                         prop = geometry->property ("y-size");
1444                 }
1445                 if (prop) {
1446                         height = atoi (prop->value());
1447                 }
1448         }
1449
1450         if (which == static_cast<Gtk::Paned*> (&rhs_pane1)) {
1451
1452                 if (done[0]) {
1453                         return;
1454                 }
1455
1456                 if (!geometry || (prop = geometry->property("mixer-rhs-pane1-pos")) == 0) {
1457                         pos = height / 3;
1458                         snprintf (buf, sizeof(buf), "%d", pos);
1459                 } else {
1460                         pos = atoi (prop->value());
1461                 }
1462
1463                 if ((done[0] = GTK_WIDGET(rhs_pane1.gobj())->allocation.height > pos)) {
1464                         rhs_pane1.set_position (pos);
1465                 }
1466
1467         } else if (which == static_cast<Gtk::Paned*> (&list_hpane)) {
1468
1469                 if (done[2]) {
1470                         return;
1471                 }
1472
1473                 if (!geometry || (prop = geometry->property("mixer-list-hpane-pos")) == 0) {
1474                         pos = 75;
1475                         snprintf (buf, sizeof(buf), "%d", pos);
1476                 } else {
1477                         pos = atoi (prop->value());
1478                 }
1479
1480                 if ((done[2] = GTK_WIDGET(list_hpane.gobj())->allocation.width > pos)) {
1481                         list_hpane.set_position (pos);
1482                 }
1483         }
1484 }
1485 void
1486 Mixer_UI::scroll_left () 
1487 {
1488         Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1489         /* stupid GTK: can't rely on clamping across versions */
1490         scroller.get_hscrollbar()->set_value (max (adj->get_lower(), adj->get_value() - adj->get_step_increment()));
1491 }
1492
1493 void
1494 Mixer_UI::scroll_right ()
1495 {
1496         Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1497         /* stupid GTK: can't rely on clamping across versions */
1498         scroller.get_hscrollbar()->set_value (min (adj->get_upper(), adj->get_value() + adj->get_step_increment()));
1499 }
1500
1501 bool
1502 Mixer_UI::on_key_press_event (GdkEventKey* ev)
1503 {
1504         switch (ev->keyval) {
1505         case GDK_Left:
1506                 scroll_left ();
1507                 return true;
1508
1509         case GDK_Right:
1510                 scroll_right ();
1511                 return true;
1512
1513         default:
1514                 break;
1515         }
1516
1517         return key_press_focus_accelerator_handler (*this, ev);
1518 }
1519
1520 bool
1521 Mixer_UI::on_key_release_event (GdkEventKey* ev)
1522 {
1523         return Gtk::Window::on_key_release_event (ev);
1524         // return key_press_focus_accelerator_handler (*this, ev);
1525 }
1526
1527
1528 bool
1529 Mixer_UI::on_scroll_event (GdkEventScroll* ev)
1530 {
1531         switch (ev->direction) {
1532         case GDK_SCROLL_LEFT:
1533                 scroll_left ();
1534                 return true;
1535         case GDK_SCROLL_UP:
1536                 if (ev->state & Keyboard::TertiaryModifier) {
1537                         scroll_left ();
1538                         return true;
1539                 }
1540                 return false;
1541
1542         case GDK_SCROLL_RIGHT:
1543                 scroll_right ();
1544                 return true;
1545
1546         case GDK_SCROLL_DOWN:
1547                 if (ev->state & Keyboard::TertiaryModifier) {
1548                         scroll_right ();
1549                         return true;
1550                 }
1551                 return false;
1552         }
1553
1554         return false;
1555 }
1556
1557
1558 void
1559 Mixer_UI::parameter_changed (string const & p)
1560 {
1561         if (p == "show-group-tabs") {
1562                 bool const s = _session->config.get_show_group_tabs ();
1563                 if (s) {
1564                         _group_tabs->show ();
1565                 } else {
1566                         _group_tabs->hide ();
1567                 }
1568         } else if (p == "default-narrow_ms") {
1569                 bool const s = Config->get_default_narrow_ms ();
1570                 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1571                         (*i)->set_width_enum (s ? Narrow : Wide, this);
1572                 }
1573         }
1574 }
1575
1576 void
1577 Mixer_UI::set_route_group_activation (RouteGroup* g, bool a)
1578 {
1579         g->set_active (a, this);
1580 }
1581
1582 PluginSelector*
1583 Mixer_UI::plugin_selector()
1584 {
1585 #ifdef DEFER_PLUGIN_SELECTOR_LOAD
1586         if (!_plugin_selector)
1587                 _plugin_selector = new PluginSelector (PluginManager::the_manager ());
1588 #endif
1589
1590         return _plugin_selector;
1591 }
1592
1593 void
1594 Mixer_UI::setup_track_display ()
1595 {
1596         track_model = ListStore::create (track_columns);
1597         track_display.set_model (track_model);
1598         track_display.append_column (_("Strips"), track_columns.text);
1599         track_display.append_column (_("Show"), track_columns.visible);
1600         track_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
1601         track_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
1602         track_display.get_column (0)->set_expand(true);
1603         track_display.get_column (1)->set_expand(false);
1604         track_display.set_name (X_("MixerTrackDisplayList"));
1605         track_display.get_selection()->set_mode (Gtk::SELECTION_NONE);
1606         track_display.set_reorderable (true);
1607         track_display.set_headers_visible (true);
1608
1609         track_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_delete));
1610         track_model->signal_row_changed().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_change));
1611         track_model->signal_rows_reordered().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_reorder));
1612
1613         CellRendererToggle* track_list_visible_cell = dynamic_cast<CellRendererToggle*>(track_display.get_column_cell_renderer (1));
1614         track_list_visible_cell->property_activatable() = true;
1615         track_list_visible_cell->property_radio() = false;
1616
1617         track_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::track_display_button_press), false);
1618
1619         track_display_scroller.add (track_display);
1620         track_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1621
1622         VBox* v = manage (new VBox);
1623         v->show ();
1624         v->pack_start (track_display_scroller, true, true);
1625
1626         Button* b = manage (new Button);
1627         b->show ();
1628         Widget* w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
1629         w->show ();
1630         b->add (*w);
1631
1632         b->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus));
1633         
1634         v->pack_start (*b, false, false);
1635
1636         track_display_frame.set_name("BaseFrame");
1637         track_display_frame.set_shadow_type (Gtk::SHADOW_IN);
1638         track_display_frame.add (*v);
1639
1640         track_display_scroller.show();
1641         track_display_frame.show();
1642         track_display.show();
1643 }
1644
1645 void
1646 Mixer_UI::new_track_or_bus ()
1647 {
1648         ARDOUR_UI::instance()->add_route (this);
1649 }