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