Set mixer strip widths when the configuration option is changed. Fixes #2855.
[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         Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::parameter_changed, this, _1), gui_context ());
519
520         route_groups_changed ();
521
522         if (_visible) {
523                 show_window();
524         }
525
526         start_updating ();
527 }
528
529 void
530 Mixer_UI::session_going_away ()
531 {
532         ENSURE_GUI_THREAD (*this, &Mixer_UI::session_going_away)
533
534         group_model->clear ();
535         _selection.clear ();
536         track_model->clear ();
537
538         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
539                 delete (*i);
540         }
541
542         if (_monitor_section) {
543                 _monitor_section->tearoff().hide_visible ();
544         }
545
546         strips.clear ();
547
548         WindowTitle title(Glib::get_application_name());
549         title += _("Mixer");
550         set_title (title.get_string());
551
552         stop_updating ();
553
554         SessionHandlePtr::session_going_away ();
555 }
556
557 void
558 Mixer_UI::show_strip (MixerStrip* ms)
559 {
560         TreeModel::Children rows = track_model->children();
561         TreeModel::Children::iterator i;
562
563         for (i = rows.begin(); i != rows.end(); ++i) {
564
565                 MixerStrip* strip = (*i)[track_columns.strip];
566                 if (strip == ms) {
567                         (*i)[track_columns.visible] = true;
568                         break;
569                 }
570         }
571 }
572
573 void
574 Mixer_UI::hide_strip (MixerStrip* ms)
575 {
576         TreeModel::Children rows = track_model->children();
577         TreeModel::Children::iterator i;
578
579         for (i = rows.begin(); i != rows.end(); ++i) {
580
581                 MixerStrip* strip = (*i)[track_columns.strip];
582                 if (strip == ms) {
583                         (*i)[track_columns.visible] = false;
584                         break;
585                 }
586         }
587 }
588
589 gint
590 Mixer_UI::start_updating ()
591 {
592     fast_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (sigc::mem_fun(*this, &Mixer_UI::fast_update_strips));
593     return 0;
594 }
595
596 gint
597 Mixer_UI::stop_updating ()
598 {
599     fast_screen_update_connection.disconnect();
600     return 0;
601 }
602
603 void
604 Mixer_UI::fast_update_strips ()
605 {
606         if (is_mapped () && _session) {
607                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
608                         (*i)->fast_update ();
609                 }
610         }
611 }
612
613 void
614 Mixer_UI::set_all_strips_visibility (bool yn)
615 {
616         TreeModel::Children rows = track_model->children();
617         TreeModel::Children::iterator i;
618
619         no_track_list_redisplay = true;
620
621         for (i = rows.begin(); i != rows.end(); ++i) {
622
623                 TreeModel::Row row = (*i);
624                 MixerStrip* strip = row[track_columns.strip];
625
626                 if (strip == 0) {
627                         continue;
628                 }
629
630                 if (strip->route()->is_master() || strip->route()->is_monitor()) {
631                         continue;
632                 }
633
634                 (*i)[track_columns.visible] = yn;
635         }
636
637         no_track_list_redisplay = false;
638         redisplay_track_list ();
639 }
640
641
642 void
643 Mixer_UI::set_all_audio_visibility (int tracks, bool yn)
644 {
645         TreeModel::Children rows = track_model->children();
646         TreeModel::Children::iterator i;
647
648         no_track_list_redisplay = true;
649
650         for (i = rows.begin(); i != rows.end(); ++i) {
651                 TreeModel::Row row = (*i);
652                 MixerStrip* strip = row[track_columns.strip];
653
654                 if (strip == 0) {
655                         continue;
656                 }
657
658                 if (strip->route()->is_master() || strip->route()->is_monitor()) {
659                         continue;
660                 }
661
662                 boost::shared_ptr<AudioTrack> at = strip->audio_track();
663
664                 switch (tracks) {
665                 case 0:
666                         (*i)[track_columns.visible] = yn;
667                         break;
668
669                 case 1:
670                         if (at) { /* track */
671                                 (*i)[track_columns.visible] = yn;
672                         }
673                         break;
674
675                 case 2:
676                         if (!at) { /* bus */
677                                 (*i)[track_columns.visible] = yn;
678                         }
679                         break;
680                 }
681         }
682
683         no_track_list_redisplay = false;
684         redisplay_track_list ();
685 }
686
687 void
688 Mixer_UI::hide_all_routes ()
689 {
690         set_all_strips_visibility (false);
691 }
692
693 void
694 Mixer_UI::show_all_routes ()
695 {
696         set_all_strips_visibility (true);
697 }
698
699 void
700 Mixer_UI::show_all_audiobus ()
701 {
702         set_all_audio_visibility (2, true);
703 }
704 void
705 Mixer_UI::hide_all_audiobus ()
706 {
707         set_all_audio_visibility (2, false);
708 }
709
710 void
711 Mixer_UI::show_all_audiotracks()
712 {
713         set_all_audio_visibility (1, true);
714 }
715 void
716 Mixer_UI::hide_all_audiotracks ()
717 {
718         set_all_audio_visibility (1, false);
719 }
720
721 void
722 Mixer_UI::track_list_reorder (const TreeModel::Path&, const TreeModel::iterator&, int* /*new_order*/)
723 {
724         strip_redisplay_does_not_sync_order_keys = true;
725         _session->set_remote_control_ids();
726         redisplay_track_list ();
727         strip_redisplay_does_not_sync_order_keys = false;
728 }
729
730 void
731 Mixer_UI::track_list_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator&)
732 {
733         // never reset order keys because of a property change
734         strip_redisplay_does_not_reset_order_keys = true;
735         _session->set_remote_control_ids();
736         redisplay_track_list ();
737         strip_redisplay_does_not_reset_order_keys = false;
738 }
739
740 void
741 Mixer_UI::track_list_delete (const Gtk::TreeModel::Path&)
742 {
743         /* this could require an order sync */
744         if (_session && !_session->deletion_in_progress()) {
745                 _session->set_remote_control_ids();
746                 redisplay_track_list ();
747         }
748 }
749
750 void
751 Mixer_UI::redisplay_track_list ()
752 {
753         TreeModel::Children rows = track_model->children();
754         TreeModel::Children::iterator i;
755         long order;
756
757         if (no_track_list_redisplay) {
758                 return;
759         }
760
761         for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
762                 MixerStrip* strip = (*i)[track_columns.strip];
763
764                 if (strip == 0) {
765                         /* we're in the middle of changing a row, don't worry */
766                         continue;
767                 }
768
769                 bool visible = (*i)[track_columns.visible];
770
771                 if (visible) {
772                         strip->set_marked_for_display (true);
773                         strip->route()->set_order_key (N_("signal"), order);
774
775                         if (!strip_redisplay_does_not_reset_order_keys) {
776                                 strip->route()->set_order_key (N_("signal"), order);
777                         }
778
779                         if (strip->packed()) {
780
781                                 if (strip->route()->is_master() || strip->route()->is_monitor()) {
782                                         out_packer.reorder_child (*strip, -1);
783                                 } else {
784                                         strip_packer.reorder_child (*strip, -1); /* put at end */
785                                 }
786
787                         } else {
788
789                                 if (strip->route()->is_master() || strip->route()->is_monitor()) {
790                                         out_packer.pack_start (*strip, false, false);
791                                 } else {
792                                         strip_packer.pack_start (*strip, false, false);
793                                 }
794                                 strip->set_packed (true);
795                                 //strip->show();
796                         }
797
798                 } else {
799
800                         strip->set_marked_for_display (false);
801
802                         if (strip->route()->is_master() || strip->route()->is_monitor()) {
803                                 /* do nothing, these cannot be hidden */
804                         } else {
805                                 if (strip->packed()) {
806                                         strip_packer.remove (*strip);
807                                         strip->set_packed (false);
808                                 }
809                         }
810                 }
811         }
812
813         if (!strip_redisplay_does_not_reset_order_keys && !strip_redisplay_does_not_sync_order_keys) {
814                 _session->sync_order_keys (N_("signal"));
815         }
816
817         // Resigc::bind all of the midi controls automatically
818
819         if (auto_rebinding)
820                 auto_rebind_midi_controls ();
821
822         _group_tabs->set_dirty ();
823 }
824
825 void
826 Mixer_UI::strip_width_changed ()
827 {
828         _group_tabs->set_dirty ();
829
830 #ifdef GTKOSX
831         TreeModel::Children rows = track_model->children();
832         TreeModel::Children::iterator i;
833         long order;
834
835         for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
836                 MixerStrip* strip = (*i)[track_columns.strip];
837
838                 if (strip == 0) {
839                         continue;
840                 }
841
842                 bool visible = (*i)[track_columns.visible];
843
844                 if (visible) {
845                         strip->queue_draw();
846                 }
847         }
848 #endif
849
850 }
851
852 void
853 Mixer_UI::set_auto_rebinding( bool val )
854 {
855         if( val == TRUE )
856         {
857                 auto_rebinding = TRUE;
858                 Session::AutoBindingOff();
859         }
860         else
861         {
862                 auto_rebinding = FALSE;
863                 Session::AutoBindingOn();
864         }
865 }
866
867 void
868 Mixer_UI::toggle_auto_rebinding()
869 {
870         if (auto_rebinding)
871         {
872                 set_auto_rebinding( FALSE );
873         }
874
875         else
876         {
877                 set_auto_rebinding( TRUE );
878         }
879
880         auto_rebind_midi_controls();
881 }
882
883 void
884 Mixer_UI::auto_rebind_midi_controls ()
885 {
886         TreeModel::Children rows = track_model->children();
887         TreeModel::Children::iterator i;
888         int pos;
889
890         // Create bindings for all visible strips and remove those that are not visible
891         pos = 1;  // 0 is reserved for the master strip
892         for (i = rows.begin(); i != rows.end(); ++i) {
893                 MixerStrip* strip = (*i)[track_columns.strip];
894
895                 if ( (*i)[track_columns.visible] == true ) {  // add bindings for
896                         // make the actual binding
897                         //cout<<"Auto Binding:  Visible Strip Found: "<<strip->name()<<endl;
898
899                         int controlValue = pos;
900                         if( strip->route()->is_master() ) {
901                                 controlValue = 0;
902                         }
903                         else {
904                                 pos++;
905                         }
906
907                         PBD::Controllable::CreateBinding ( strip->solo_button->get_controllable().get(), controlValue, 0);
908                         PBD::Controllable::CreateBinding ( strip->mute_button->get_controllable().get(), controlValue, 1);
909
910                         if( strip->is_audio_track() ) {
911                                 PBD::Controllable::CreateBinding ( strip->rec_enable_button->get_controllable().get(), controlValue, 2);
912                         }
913
914                         PBD::Controllable::CreateBinding ( strip->gpm.get_controllable().get(), controlValue, 3);
915                         PBD::Controllable::CreateBinding ( strip->panners.get_controllable().get(), controlValue, 4);
916
917                 }
918                 else {  // Remove any existing binding
919                         PBD::Controllable::DeleteBinding ( strip->solo_button->get_controllable().get() );
920                         PBD::Controllable::DeleteBinding ( strip->mute_button->get_controllable().get() );
921
922                         if( strip->is_audio_track() ) {
923                                 PBD::Controllable::DeleteBinding ( strip->rec_enable_button->get_controllable().get() );
924                         }
925
926                         PBD::Controllable::DeleteBinding ( strip->gpm.get_controllable().get() );
927                         PBD::Controllable::DeleteBinding ( strip->panners.get_controllable().get() ); // This only takes the first panner if there are multiples...
928                 }
929
930         } // for
931
932 }
933
934 struct SignalOrderRouteSorter {
935     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
936             /* use of ">" forces the correct sort order */
937             return a->order_key (N_("signal")) < b->order_key (N_("signal"));
938     }
939 };
940
941 void
942 Mixer_UI::initial_track_display ()
943 {
944         boost::shared_ptr<RouteList> routes = _session->get_routes();
945         RouteList copy (*routes);
946         SignalOrderRouteSorter sorter;
947
948         copy.sort (sorter);
949
950         no_track_list_redisplay = true;
951
952         track_model->clear ();
953
954         add_strip (copy);
955
956         no_track_list_redisplay = false;
957
958         redisplay_track_list ();
959 }
960
961 void
962 Mixer_UI::show_track_list_menu ()
963 {
964         if (track_menu == 0) {
965                 build_track_menu ();
966         }
967
968         track_menu->popup (1, gtk_get_current_event_time());
969 }
970
971 bool
972 Mixer_UI::track_display_button_press (GdkEventButton* ev)
973 {
974         if (Keyboard::is_context_menu_event (ev)) {
975                 show_track_list_menu ();
976                 return true;
977         }
978
979         TreeIter iter;
980         TreeModel::Path path;
981         TreeViewColumn* column;
982         int cellx;
983         int celly;
984
985         if (!track_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
986                 return false;
987         }
988
989         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
990         case 0:
991                 /* allow normal processing to occur */
992                 return false;
993
994         case 1: /* visibility */
995
996                 if ((iter = track_model->get_iter (path))) {
997                         MixerStrip* strip = (*iter)[track_columns.strip];
998                         if (strip) {
999
1000                                 if (!strip->route()->is_master() && !strip->route()->is_monitor()) {
1001                                         bool visible = (*iter)[track_columns.visible];
1002                                         (*iter)[track_columns.visible] = !visible;
1003                                 }
1004 #ifdef GTKOSX
1005                                 track_display.queue_draw();
1006 #endif
1007                         }
1008                 }
1009                 return true;
1010
1011         default:
1012                 break;
1013         }
1014
1015         return false;
1016 }
1017
1018
1019 void
1020 Mixer_UI::build_track_menu ()
1021 {
1022         using namespace Menu_Helpers;
1023         using namespace Gtk;
1024
1025         track_menu = new Menu;
1026         track_menu->set_name ("ArdourContextMenu");
1027         MenuList& items = track_menu->items();
1028
1029         items.push_back (MenuElem (_("Show All"), sigc::mem_fun(*this, &Mixer_UI::show_all_routes)));
1030         items.push_back (MenuElem (_("Hide All"), sigc::mem_fun(*this, &Mixer_UI::hide_all_routes)));
1031         items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
1032         items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
1033         items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus)));
1034         items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
1035
1036 }
1037
1038 void
1039 Mixer_UI::strip_property_changed (const PropertyChange& what_changed, MixerStrip* mx)
1040 {
1041         if (!what_changed.contains (ARDOUR::Properties::name)) {
1042                 return;
1043         }
1044
1045         ENSURE_GUI_THREAD (*this, &Mixer_UI::strip_name_changed, what_changed, mx)
1046
1047         TreeModel::Children rows = track_model->children();
1048         TreeModel::Children::iterator i;
1049
1050         for (i = rows.begin(); i != rows.end(); ++i) {
1051                 if ((*i)[track_columns.strip] == mx) {
1052                         (*i)[track_columns.text] = mx->route()->name();
1053                         return;
1054                 }
1055         }
1056
1057         error << _("track display list item for renamed strip not found!") << endmsg;
1058 }
1059
1060
1061 void
1062 Mixer_UI::build_route_group_context_menu ()
1063 {
1064         using namespace Gtk::Menu_Helpers;
1065
1066         route_group_context_menu = new Menu;
1067         route_group_context_menu->set_name ("ArdourContextMenu");
1068         MenuList& items = route_group_context_menu->items();
1069
1070         items.push_back (MenuElem (_("Activate All"), sigc::mem_fun(*this, &Mixer_UI::activate_all_route_groups)));
1071         items.push_back (MenuElem (_("Disable All"), sigc::mem_fun(*this, &Mixer_UI::disable_all_route_groups)));
1072         items.push_back (SeparatorElem());
1073         items.push_back (MenuElem (_("Add group"), sigc::mem_fun(*this, &Mixer_UI::new_route_group)));
1074
1075 }
1076
1077 bool
1078 Mixer_UI::group_display_button_press (GdkEventButton* ev)
1079 {
1080         if (Keyboard::is_context_menu_event (ev)) {
1081                 if (route_group_context_menu == 0) {
1082                         build_route_group_context_menu ();
1083                 }
1084                 route_group_context_menu->popup (1, ev->time);
1085                 return true;
1086         }
1087
1088
1089         RouteGroup* group;
1090         TreeIter iter;
1091         TreeModel::Path path;
1092         TreeViewColumn* column;
1093         int cellx;
1094         int celly;
1095
1096         if (!group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
1097                 return false;
1098         }
1099
1100         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
1101         case 0:
1102                 if (Keyboard::is_edit_event (ev)) {
1103                         if ((iter = group_model->get_iter (path))) {
1104                                 if ((group = (*iter)[group_columns.group]) != 0) {
1105                                         // edit_route_group (group);
1106 #ifdef GTKOSX
1107                                         group_display.queue_draw();
1108 #endif
1109                                         return true;
1110                                 }
1111                         }
1112
1113                 }
1114                 break;
1115
1116         case 1:
1117                 if ((iter = group_model->get_iter (path))) {
1118                         bool visible = (*iter)[group_columns.visible];
1119                         (*iter)[group_columns.visible] = !visible;
1120 #ifdef GTKOSX
1121                         group_display.queue_draw();
1122 #endif
1123                         return true;
1124                 }
1125                 break;
1126
1127         default:
1128                 break;
1129         }
1130
1131         return false;
1132  }
1133
1134 void
1135 Mixer_UI::activate_all_route_groups ()
1136 {
1137         _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), true));
1138 }
1139
1140 void
1141 Mixer_UI::disable_all_route_groups ()
1142 {
1143         _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), false));
1144 }
1145
1146 void
1147 Mixer_UI::route_groups_changed ()
1148 {
1149         ENSURE_GUI_THREAD (*this, &Mixer_UI::route_groups_changed)
1150
1151         /* just rebuild the while thing */
1152
1153         group_model->clear ();
1154
1155         {
1156                 TreeModel::Row row;
1157                 row = *(group_model->append());
1158                 row[group_columns.visible] = true;
1159                 row[group_columns.text] = (_("-all-"));
1160                 row[group_columns.group] = 0;
1161         }
1162
1163         _session->foreach_route_group (sigc::mem_fun (*this, &Mixer_UI::add_route_group));
1164 }
1165
1166 void
1167 Mixer_UI::new_route_group ()
1168 {
1169         PropertyList plist;
1170
1171         plist.add (Properties::active, true);
1172         plist.add (Properties::gain, true);
1173         plist.add (Properties::mute, true);
1174         plist.add (Properties::solo, true);
1175
1176         RouteGroup* g = new RouteGroup (*_session, "");
1177         g->set_properties (plist);
1178
1179         _session->add_route_group (g);
1180 }
1181
1182 void
1183 Mixer_UI::remove_selected_route_group ()
1184 {
1185         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1186         TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1187
1188         if (rows.empty()) {
1189                 return;
1190         }
1191
1192         TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1193         TreeIter iter;
1194
1195         /* selection mode is single, so rows.begin() is it */
1196
1197         if ((iter = group_model->get_iter (*i))) {
1198
1199                 RouteGroup* rg = (*iter)[group_columns.group];
1200
1201                 if (rg) {
1202                         _session->remove_route_group (*rg);
1203                 }
1204         }
1205 }
1206
1207 void
1208 Mixer_UI::route_group_property_changed (RouteGroup* group, const PropertyChange& change)
1209 {
1210         if (in_group_row_change) {
1211                 return;
1212         }
1213
1214         /* force an update of any mixer strips that are using this group,
1215            otherwise mix group names don't change in mixer strips
1216         */
1217
1218         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1219                 if ((*i)->route_group() == group) {
1220                         (*i)->route_group_changed();
1221                 }
1222         }
1223
1224         TreeModel::iterator i;
1225         TreeModel::Children rows = group_model->children();
1226         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1227
1228         in_group_row_change = true;
1229
1230         for (i = rows.begin(); i != rows.end(); ++i) {
1231                 if ((*i)[group_columns.group] == group) {
1232                         (*i)[group_columns.visible] = !group->is_hidden ();
1233                         (*i)[group_columns.text] = group->name ();
1234                         break;
1235                 }
1236         }
1237
1238         in_group_row_change = false;
1239
1240         if (change.contains (Properties::name)) {
1241                 _group_tabs->set_dirty ();
1242         }
1243 }
1244
1245 void
1246 Mixer_UI::route_group_name_edit (const Glib::ustring& path, const Glib::ustring& new_text)
1247 {
1248         RouteGroup* group;
1249         TreeIter iter;
1250
1251         if ((iter = group_model->get_iter (path))) {
1252
1253                 if ((group = (*iter)[group_columns.group]) == 0) {
1254                         return;
1255                 }
1256
1257                 if (new_text != group->name()) {
1258                         group->set_name (new_text);
1259                 }
1260         }
1261 }
1262
1263 void
1264 Mixer_UI::route_group_row_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator& iter)
1265 {
1266         RouteGroup* group;
1267
1268         if (in_group_row_change) {
1269                 return;
1270         }
1271
1272         if ((group = (*iter)[group_columns.group]) == 0) {
1273                 return;
1274         }
1275
1276         if ((*iter)[group_columns.visible]) {
1277                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1278                         if ((*i)->route_group() == group) {
1279                                 show_strip (*i);
1280                         }
1281                 }
1282         } else {
1283                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1284                         if ((*i)->route_group() == group) {
1285                                 hide_strip (*i);
1286                         }
1287                 }
1288         }
1289
1290         Glib::ustring name = (*iter)[group_columns.text];
1291
1292         if (name != group->name()) {
1293                 group->set_name (name);
1294         }
1295
1296 }
1297
1298 void
1299 Mixer_UI::add_route_group (RouteGroup* group)
1300 {
1301         ENSURE_GUI_THREAD (*this, &Mixer_UI::add_route_group, group)
1302         bool focus = false;
1303
1304         in_group_row_change = true;
1305
1306         TreeModel::Row row = *(group_model->append());
1307         row[group_columns.visible] = true;
1308         row[group_columns.group] = group;
1309         if (!group->name().empty()) {
1310                 row[group_columns.text] = group->name();
1311         } else {
1312                 row[group_columns.text] = _("unnamed");
1313                 focus = true;
1314         }
1315
1316         group->PropertyChanged.connect (*this, invalidator (*this), ui_bind (&Mixer_UI::route_group_property_changed, this, group, _1), gui_context());
1317
1318         if (focus) {
1319                 TreeViewColumn* col = group_display.get_column (0);
1320                 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
1321                 group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true);
1322         }
1323
1324         in_group_row_change = false;
1325 }
1326
1327 bool
1328 Mixer_UI::strip_scroller_button_release (GdkEventButton* ev)
1329 {
1330         using namespace Menu_Helpers;
1331
1332         if (Keyboard::is_context_menu_event (ev)) {
1333                 ARDOUR_UI::instance()->add_route (this);
1334                 return true;
1335         }
1336
1337         return false;
1338 }
1339
1340 void
1341 Mixer_UI::set_strip_width (Width w)
1342 {
1343         _strip_width = w;
1344
1345         for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1346                 (*i)->set_width_enum (w, this);
1347         }
1348 }
1349
1350 void
1351 Mixer_UI::set_window_pos_and_size ()
1352 {
1353         resize (m_width, m_height);
1354         move (m_root_x, m_root_y);
1355 }
1356
1357         void
1358 Mixer_UI::get_window_pos_and_size ()
1359 {
1360         get_position(m_root_x, m_root_y);
1361         get_size(m_width, m_height);
1362 }
1363
1364 int
1365 Mixer_UI::set_state (const XMLNode& node)
1366 {
1367         const XMLProperty* prop;
1368         XMLNode* geometry;
1369
1370         m_width = default_width;
1371         m_height = default_height;
1372         m_root_x = 1;
1373         m_root_y = 1;
1374
1375         if ((geometry = find_named_node (node, "geometry")) != 0) {
1376
1377                 XMLProperty* prop;
1378
1379                 if ((prop = geometry->property("x_size")) == 0) {
1380                         prop = geometry->property ("x-size");
1381                 }
1382                 if (prop) {
1383                         m_width = atoi(prop->value());
1384                 }
1385                 if ((prop = geometry->property("y_size")) == 0) {
1386                         prop = geometry->property ("y-size");
1387                 }
1388                 if (prop) {
1389                         m_height = atoi(prop->value());
1390                 }
1391
1392                 if ((prop = geometry->property ("x_pos")) == 0) {
1393                         prop = geometry->property ("x-pos");
1394                 }
1395                 if (prop) {
1396                         m_root_x = atoi (prop->value());
1397
1398                 }
1399                 if ((prop = geometry->property ("y_pos")) == 0) {
1400                         prop = geometry->property ("y-pos");
1401                 }
1402                 if (prop) {
1403                         m_root_y = atoi (prop->value());
1404                 }
1405         }
1406
1407         set_window_pos_and_size ();
1408
1409         if ((prop = node.property ("narrow-strips"))) {
1410                 if (string_is_affirmative (prop->value())) {
1411                         set_strip_width (Narrow);
1412                 } else {
1413                         set_strip_width (Wide);
1414                 }
1415         }
1416
1417         if ((prop = node.property ("show-mixer"))) {
1418                 if (string_is_affirmative (prop->value())) {
1419                        _visible = true;
1420                 }
1421         }
1422
1423         return 0;
1424 }
1425
1426 XMLNode&
1427 Mixer_UI::get_state (void)
1428 {
1429         XMLNode* node = new XMLNode ("Mixer");
1430
1431         if (is_realized()) {
1432                 Glib::RefPtr<Gdk::Window> win = get_window();
1433
1434                 get_window_pos_and_size ();
1435
1436                 XMLNode* geometry = new XMLNode ("geometry");
1437                 char buf[32];
1438                 snprintf(buf, sizeof(buf), "%d", m_width);
1439                 geometry->add_property(X_("x_size"), string(buf));
1440                 snprintf(buf, sizeof(buf), "%d", m_height);
1441                 geometry->add_property(X_("y_size"), string(buf));
1442                 snprintf(buf, sizeof(buf), "%d", m_root_x);
1443                 geometry->add_property(X_("x_pos"), string(buf));
1444                 snprintf(buf, sizeof(buf), "%d", m_root_y);
1445                 geometry->add_property(X_("y_pos"), string(buf));
1446
1447                 // written only for compatibility, they are not used.
1448                 snprintf(buf, sizeof(buf), "%d", 0);
1449                 geometry->add_property(X_("x_off"), string(buf));
1450                 snprintf(buf, sizeof(buf), "%d", 0);
1451                 geometry->add_property(X_("y_off"), string(buf));
1452
1453                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&rhs_pane1)->gobj()));
1454                 geometry->add_property(X_("mixer_rhs_pane1_pos"), string(buf));
1455                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&list_hpane)->gobj()));
1456                 geometry->add_property(X_("mixer_list_hpane_pos"), string(buf));
1457
1458                 node->add_child_nocopy (*geometry);
1459         }
1460
1461         node->add_property ("narrow-strips", _strip_width == Narrow ? "yes" : "no");
1462
1463         node->add_property ("show-mixer", _visible ? "yes" : "no");
1464
1465         return *node;
1466 }
1467
1468
1469 void
1470 Mixer_UI::pane_allocation_handler (Allocation&, Gtk::Paned* which)
1471 {
1472         int pos;
1473         XMLProperty* prop = 0;
1474         char buf[32];
1475         XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
1476         XMLNode* geometry;
1477         int width, height;
1478         static int32_t done[3] = { 0, 0, 0 };
1479
1480         width = default_width;
1481         height = default_height;
1482
1483         if ((geometry = find_named_node (*node, "geometry")) != 0) {
1484
1485
1486                 if ((prop = geometry->property ("x_size")) == 0) {
1487                         prop = geometry->property ("x-size");
1488                 }
1489                 if (prop) {
1490                         width = atoi (prop->value());
1491                 }
1492                 if ((prop = geometry->property ("y_size")) == 0) {
1493                         prop = geometry->property ("y-size");
1494                 }
1495                 if (prop) {
1496                         height = atoi (prop->value());
1497                 }
1498         }
1499
1500         if (which == static_cast<Gtk::Paned*> (&rhs_pane1)) {
1501
1502                 if (done[0]) {
1503                         return;
1504                 }
1505
1506                 if (!geometry || (prop = geometry->property("mixer-rhs-pane1-pos")) == 0) {
1507                         pos = height / 3;
1508                         snprintf (buf, sizeof(buf), "%d", pos);
1509                 } else {
1510                         pos = atoi (prop->value());
1511                 }
1512
1513                 if ((done[0] = GTK_WIDGET(rhs_pane1.gobj())->allocation.height > pos)) {
1514                         rhs_pane1.set_position (pos);
1515                 }
1516
1517         } else if (which == static_cast<Gtk::Paned*> (&list_hpane)) {
1518
1519                 if (done[2]) {
1520                         return;
1521                 }
1522
1523                 if (!geometry || (prop = geometry->property("mixer-list-hpane-pos")) == 0) {
1524                         pos = 75;
1525                         snprintf (buf, sizeof(buf), "%d", pos);
1526                 } else {
1527                         pos = atoi (prop->value());
1528                 }
1529
1530                 if ((done[2] = GTK_WIDGET(list_hpane.gobj())->allocation.width > pos)) {
1531                         list_hpane.set_position (pos);
1532                 }
1533         }
1534 }
1535 void
1536 Mixer_UI::scroll_left () 
1537 {
1538         Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1539         /* stupid GTK: can't rely on clamping across versions */
1540         scroller.get_hscrollbar()->set_value (max (adj->get_lower(), adj->get_value() - adj->get_step_increment()));
1541 }
1542
1543 void
1544 Mixer_UI::scroll_right ()
1545 {
1546         Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1547         /* stupid GTK: can't rely on clamping across versions */
1548         scroller.get_hscrollbar()->set_value (min (adj->get_upper(), adj->get_value() + adj->get_step_increment()));
1549 }
1550
1551 bool
1552 Mixer_UI::on_key_press_event (GdkEventKey* ev)
1553 {
1554         switch (ev->keyval) {
1555         case GDK_Left:
1556                 scroll_left ();
1557                 return true;
1558
1559         case GDK_Right:
1560                 scroll_right ();
1561                 return true;
1562
1563         default:
1564                 break;
1565         }
1566
1567         return key_press_focus_accelerator_handler (*this, ev);
1568 }
1569
1570 bool
1571 Mixer_UI::on_key_release_event (GdkEventKey* ev)
1572 {
1573         return Gtk::Window::on_key_release_event (ev);
1574         // return key_press_focus_accelerator_handler (*this, ev);
1575 }
1576
1577
1578 bool
1579 Mixer_UI::on_scroll_event (GdkEventScroll* ev)
1580 {
1581         switch (ev->direction) {
1582         case GDK_SCROLL_LEFT:
1583                 scroll_left ();
1584                 return true;
1585         case GDK_SCROLL_UP:
1586                 if (ev->state & Keyboard::TertiaryModifier) {
1587                         scroll_left ();
1588                         return true;
1589                 }
1590                 return false;
1591
1592         case GDK_SCROLL_RIGHT:
1593                 scroll_right ();
1594                 return true;
1595
1596         case GDK_SCROLL_DOWN:
1597                 if (ev->state & Keyboard::TertiaryModifier) {
1598                         scroll_right ();
1599                         return true;
1600                 }
1601                 return false;
1602         }
1603
1604         return false;
1605 }
1606
1607
1608 void
1609 Mixer_UI::parameter_changed (string const & p)
1610 {
1611         if (p == "show-group-tabs") {
1612                 bool const s = _session->config.get_show_group_tabs ();
1613                 if (s) {
1614                         _group_tabs->show ();
1615                 } else {
1616                         _group_tabs->hide ();
1617                 }
1618         } else if (p == "default-narrow_ms") {
1619                 bool const s = Config->get_default_narrow_ms ();
1620                 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1621                         (*i)->set_width_enum (s ? Narrow : Wide, this);
1622                 }
1623         }
1624 }
1625
1626 void
1627 Mixer_UI::set_route_group_activation (RouteGroup* g, bool a)
1628 {
1629         g->set_active (a, this);
1630 }
1631
1632 PluginSelector*
1633 Mixer_UI::plugin_selector()
1634 {
1635 #ifdef DEFER_PLUGIN_SELECTOR_LOAD
1636         if (!_plugin_selector)
1637                 _plugin_selector = new PluginSelector (PluginManager::the_manager ());
1638 #endif
1639
1640         return _plugin_selector;
1641 }