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