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