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