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