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