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