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