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