Clicking an automation track line without a move adds a point on the line.
[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 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 #include <algorithm>
25 #include <map>
26 #include <sigc++/bind.h>
27
28 #include <gtkmm/accelmap.h>
29
30 #include "pbd/convert.h"
31 #include "pbd/unwind.h"
32
33 #include <glibmm/threads.h>
34
35 #include <gtkmm2ext/gtk_ui.h>
36 #include <gtkmm2ext/utils.h>
37 #include <gtkmm2ext/tearoff.h>
38 #include <gtkmm2ext/window_title.h>
39
40 #include "ardour/debug.h"
41 #include "ardour/midi_track.h"
42 #include "ardour/plugin_manager.h"
43 #include "ardour/route_group.h"
44 #include "ardour/route_sorters.h"
45 #include "ardour/session.h"
46
47 #include "keyboard.h"
48 #include "mixer_ui.h"
49 #include "mixer_strip.h"
50 #include "monitor_section.h"
51 #include "plugin_selector.h"
52 #include "public_editor.h"
53 #include "ardour_ui.h"
54 #include "prompter.h"
55 #include "utils.h"
56 #include "route_sorter.h"
57 #include "actions.h"
58 #include "gui_thread.h"
59 #include "mixer_group_tabs.h"
60 #include "timers.h"
61
62 #include "i18n.h"
63
64 using namespace ARDOUR;
65 using namespace ARDOUR_UI_UTILS;
66 using namespace PBD;
67 using namespace Gtk;
68 using namespace Glib;
69 using namespace Gtkmm2ext;
70 using namespace std;
71
72 using PBD::atoi;
73 using PBD::Unwinder;
74
75 Mixer_UI* Mixer_UI::_instance = 0;
76
77 Mixer_UI*
78 Mixer_UI::instance () 
79 {
80         if (!_instance) {
81                 _instance  = new Mixer_UI;
82         } 
83
84         return _instance;
85 }
86
87 Mixer_UI::Mixer_UI ()
88         : Window (Gtk::WINDOW_TOPLEVEL)
89         , VisibilityTracker (*((Gtk::Window*) this))
90         , _visible (false)
91         , no_track_list_redisplay (false)
92         , in_group_row_change (false)
93         , track_menu (0)
94         , _monitor_section (0)
95         , _strip_width (ARDOUR_UI::config()->get_default_narrow_ms() ? Narrow : Wide)
96         , ignore_reorder (false)
97         , _in_group_rebuild_or_clear (false)
98         , _route_deletion_in_progress (false)
99         , _following_editor_selection (false)
100         , _maximised (false)
101 {
102         /* allow this window to become the key focus window */
103         set_flags (CAN_FOCUS);
104
105         Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::sync_treeview_from_order_keys, this), gui_context());
106
107         scroller.set_can_default (true);
108         set_default (scroller);
109
110         scroller_base.set_flags (Gtk::CAN_FOCUS);
111         scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
112         scroller_base.set_name ("MixerWindow");
113         scroller_base.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::strip_scroller_button_release));
114         // add as last item of strip packer
115         strip_packer.pack_end (scroller_base, true, true);
116
117         _group_tabs = new MixerGroupTabs (this);
118         VBox* b = manage (new VBox);
119         b->pack_start (*_group_tabs, PACK_SHRINK);
120         b->pack_start (strip_packer);
121         b->show_all ();
122
123         scroller.add (*b);
124         scroller.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC);
125
126         setup_track_display ();
127
128         group_model = ListStore::create (group_columns);
129         group_display.set_model (group_model);
130         group_display.append_column (_("Group"), group_columns.text);
131         group_display.append_column (_("Show"), group_columns.visible);
132         group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
133         group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
134         group_display.get_column (0)->set_expand(true);
135         group_display.get_column (1)->set_expand(false);
136         group_display.set_name ("EditGroupList");
137         group_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
138         group_display.set_reorderable (true);
139         group_display.set_headers_visible (true);
140         group_display.set_rules_hint (true);
141
142         /* name is directly editable */
143
144         CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
145         name_cell->property_editable() = true;
146         name_cell->signal_edited().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_name_edit));
147
148         /* use checkbox for the active column */
149
150         CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(group_display.get_column_cell_renderer (1));
151         active_cell->property_activatable() = true;
152         active_cell->property_radio() = false;
153
154         group_model->signal_row_changed().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_change));
155         /* We use this to notice drag-and-drop reorders of the group list */
156         group_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_deleted));
157         group_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::group_display_button_press), false);
158
159         group_display_scroller.add (group_display);
160         group_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
161
162         HBox* route_group_display_button_box = manage (new HBox());
163
164         Button* route_group_add_button = manage (new Button ());
165         Button* route_group_remove_button = manage (new Button ());
166
167         Widget* w;
168
169         w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
170         w->show();
171         route_group_add_button->add (*w);
172
173         w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
174         w->show();
175         route_group_remove_button->add (*w);
176
177         route_group_display_button_box->set_homogeneous (true);
178
179         route_group_add_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_route_group));
180         route_group_remove_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::remove_selected_route_group));
181
182         route_group_display_button_box->add (*route_group_add_button);
183         route_group_display_button_box->add (*route_group_remove_button);
184
185         group_display_vbox.pack_start (group_display_scroller, true, true);
186         group_display_vbox.pack_start (*route_group_display_button_box, false, false);
187
188         group_display_frame.set_name ("BaseFrame");
189         group_display_frame.set_shadow_type (Gtk::SHADOW_IN);
190         group_display_frame.add (group_display_vbox);
191
192         rhs_pane1.pack1 (track_display_frame);
193         rhs_pane1.pack2 (group_display_frame);
194
195         list_vpacker.pack_start (rhs_pane1, true, true);
196
197         global_hpacker.pack_start (scroller, true, true);
198 #ifdef GTKOSX
199         /* current gtk-quartz has dirty updates on borders like this one */
200         global_hpacker.pack_start (out_packer, false, false, 0);
201 #else
202         global_hpacker.pack_start (out_packer, false, false, 12);
203 #endif
204         list_hpane.pack1(list_vpacker, false, false);
205         list_hpane.pack2(global_hpacker, true, false);
206
207         rhs_pane1.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
208                                                         static_cast<Gtk::Paned*> (&rhs_pane1)));
209         list_hpane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
210                                                          static_cast<Gtk::Paned*> (&list_hpane)));
211
212         global_vpacker.pack_start (list_hpane, true, true);
213
214         add (global_vpacker);
215         set_name ("MixerWindow");
216
217         update_title ();
218
219         set_wmclass (X_("ardour_mixer"), PROGRAM_NAME);
220
221         signal_delete_event().connect (sigc::mem_fun (*this, &Mixer_UI::hide_window));
222         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
223
224         signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
225
226         route_group_display_button_box->show();
227         route_group_add_button->show();
228         route_group_remove_button->show();
229
230         global_hpacker.show();
231         global_vpacker.show();
232         scroller.show();
233         scroller_base.show();
234         scroller_hpacker.show();
235         mixer_scroller_vpacker.show();
236         list_vpacker.show();
237         group_display_button_label.show();
238         group_display_button.show();
239         group_display_scroller.show();
240         group_display_vbox.show();
241         group_display_frame.show();
242         rhs_pane1.show();
243         strip_packer.show();
244         out_packer.show();
245         list_hpane.show();
246         group_display.show();
247
248         MixerStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_strip, this, _1), gui_context());
249
250 #ifndef DEFER_PLUGIN_SELECTOR_LOAD
251         _plugin_selector = new PluginSelector (PluginManager::instance ());
252 #endif
253 }
254
255 Mixer_UI::~Mixer_UI ()
256 {
257         if (_monitor_section) {
258                 delete _monitor_section;
259         }
260 }
261
262 void
263 Mixer_UI::track_editor_selection ()
264 {
265         PublicEditor::instance().get_selection().TracksChanged.connect (sigc::mem_fun (*this, &Mixer_UI::follow_editor_selection));
266 }
267
268
269 void
270 Mixer_UI::ensure_float (Window& win)
271 {
272         win.set_transient_for (*this);
273 }
274
275 void
276 Mixer_UI::show_window ()
277 {
278         present ();
279         if (!_visible) {
280                 set_window_pos_and_size ();
281
282                 /* show/hide group tabs as required */
283                 parameter_changed ("show-group-tabs");
284
285                 /* now reset each strips width so the right widgets are shown */
286                 MixerStrip* ms;
287
288                 TreeModel::Children rows = track_model->children();
289                 TreeModel::Children::iterator ri;
290
291                 for (ri = rows.begin(); ri != rows.end(); ++ri) {
292                         ms = (*ri)[track_columns.strip];
293                         ms->set_width_enum (ms->get_width_enum (), ms->width_owner());
294                         /* Fix visibility of mixer strip stuff */
295                         ms->parameter_changed (X_("mixer-element-visibility"));
296                 }
297         }
298         
299         /* force focus into main area */
300         scroller_base.grab_focus ();
301
302         _visible = true;
303 }
304
305 bool
306 Mixer_UI::hide_window (GdkEventAny *ev)
307 {
308         get_window_pos_and_size ();
309
310         _visible = false;
311         return just_hide_it(ev, static_cast<Gtk::Window *>(this));
312 }
313
314
315 void
316 Mixer_UI::add_strips (RouteList& routes)
317 {
318         bool from_scratch = track_model->children().size() == 0;
319         Gtk::TreeModel::Children::iterator insert_iter = track_model->children().end();
320
321         for (Gtk::TreeModel::Children::iterator it = track_model->children().begin(); it != track_model->children().end(); ++it) {
322                 boost::shared_ptr<Route> r = (*it)[track_columns.route];
323
324                 if (r->order_key() == (routes.front()->order_key() + routes.size())) {
325                         insert_iter = it;
326                         break;
327                 }
328         }
329
330         if(!from_scratch) {
331                 _selection.clear_routes ();
332         }
333
334         MixerStrip* strip;
335
336         try {
337                 no_track_list_redisplay = true;
338                 track_display.set_model (Glib::RefPtr<ListStore>());
339
340                 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
341                         boost::shared_ptr<Route> route = (*x);
342                         
343                         if (route->is_auditioner()) {
344                                 continue;
345                         }
346                         
347                         if (route->is_monitor()) {
348                                 
349                                 if (!_monitor_section) {
350                                         _monitor_section = new MonitorSection (_session);
351                                         
352                                         XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
353                                         if (mnode) {
354                                                 _monitor_section->tearoff().set_state (*mnode);
355                                         }
356                                 } 
357                                 
358                                 out_packer.pack_end (_monitor_section->tearoff(), false, false);
359                                 _monitor_section->set_session (_session);
360                                 _monitor_section->tearoff().show_all ();
361                                 
362                                 route->DropReferences.connect (*this, invalidator(*this), boost::bind (&Mixer_UI::monitor_section_going_away, this), gui_context());
363                                 
364                                 /* no regular strip shown for control out */
365                                 
366                                 continue;
367                         }
368                         
369                         strip = new MixerStrip (*this, _session, route);
370                         strips.push_back (strip);
371
372                         ARDOUR_UI::config()->get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide;
373                         
374                         if (strip->width_owner() != strip) {
375                                 strip->set_width_enum (_strip_width, this);
376                         }
377                         
378                         show_strip (strip);
379                         
380                         TreeModel::Row row = *(track_model->insert(insert_iter));
381                         row[track_columns.text] = route->name();
382                         row[track_columns.visible] = strip->route()->is_master() ? true : strip->marked_for_display();
383                         row[track_columns.route] = route;
384                         row[track_columns.strip] = strip;
385
386                         if (!from_scratch) {
387                                 _selection.add (strip);
388                         }
389                         
390                         route->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::strip_property_changed, this, _1, strip), gui_context());
391                         
392                         strip->WidthChanged.connect (sigc::mem_fun(*this, &Mixer_UI::strip_width_changed));
393                         strip->signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::strip_button_release_event), strip));
394                 }
395
396         } catch (...) {
397         }
398
399         no_track_list_redisplay = false;
400         track_display.set_model (track_model);
401         
402         sync_order_keys_from_treeview ();
403         redisplay_track_list ();
404 }
405
406 void
407 Mixer_UI::deselect_all_strip_processors ()
408 {
409         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
410                 (*i)->deselect_all_processors();
411         }
412 }
413
414 void
415 Mixer_UI::select_none ()
416 {
417         _selection.clear_routes();
418         deselect_all_strip_processors();
419 }
420
421 void
422 Mixer_UI::delete_processors ()
423 {
424         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
425                 (*i)->delete_processors();
426         }
427 }
428
429
430 void
431 Mixer_UI::remove_strip (MixerStrip* strip)
432 {
433         if (_session && _session->deletion_in_progress()) {
434                 /* its all being taken care of */
435                 return;
436         }
437
438         TreeModel::Children rows = track_model->children();
439         TreeModel::Children::iterator ri;
440         list<MixerStrip *>::iterator i;
441         
442         if ((i = find (strips.begin(), strips.end(), strip)) != strips.end()) {
443                 strips.erase (i);
444         }
445         
446         for (ri = rows.begin(); ri != rows.end(); ++ri) {
447                 if ((*ri)[track_columns.strip] == strip) {
448                         PBD::Unwinder<bool> uw (_route_deletion_in_progress, true);
449                         track_model->erase (ri);
450                         break;
451                 }
452         }
453 }
454
455 void
456 Mixer_UI::reset_remote_control_ids ()
457 {
458         if (Config->get_remote_model() == UserOrdered || !_session || _session->deletion_in_progress()) {
459                 return;
460         }
461
462         TreeModel::Children rows = track_model->children();
463         
464         if (rows.empty()) {
465                 return;
466         }
467
468         DEBUG_TRACE (DEBUG::OrderKeys, "mixer resets remote control ids after remote model change\n");
469
470         TreeModel::Children::iterator ri;
471         bool rid_change = false;
472         uint32_t rid = 1;
473         uint32_t invisible_key = UINT32_MAX;
474
475         for (ri = rows.begin(); ri != rows.end(); ++ri) {
476
477                 /* skip two special values */
478                 
479                 if (rid == Route::MasterBusRemoteControlID) {
480                         rid++;
481                 }
482                 
483                 if (rid == Route::MonitorBusRemoteControlID) {
484                         rid++;
485                 }
486
487                 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
488                 bool visible = (*ri)[track_columns.visible];
489
490                 if (!route->is_master() && !route->is_monitor()) {
491                         
492                         uint32_t new_rid = (visible ? rid : invisible_key--);
493                         
494                         if (new_rid != route->remote_control_id()) {
495                                 route->set_remote_control_id_explicit (new_rid);        
496                                 rid_change = true;
497                         }
498                         
499                         if (visible) {
500                                 rid++;
501                         }
502                 }
503         }
504
505         if (rid_change) {
506                 /* tell the world that we changed the remote control IDs */
507                 _session->notify_remote_id_change ();
508         }
509 }
510
511 void
512 Mixer_UI::sync_order_keys_from_treeview ()
513 {
514         if (ignore_reorder || !_session || _session->deletion_in_progress()) {
515                 return;
516         }
517
518         TreeModel::Children rows = track_model->children();
519         
520         if (rows.empty()) {
521                 return;
522         }
523
524         DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync order keys from model\n");
525
526         TreeModel::Children::iterator ri;
527         bool changed = false;
528         bool rid_change = false;
529         uint32_t order = 0;
530         uint32_t rid = 1;
531         uint32_t invisible_key = UINT32_MAX;
532
533         for (ri = rows.begin(); ri != rows.end(); ++ri) {
534                 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
535                 bool visible = (*ri)[track_columns.visible];
536
537                 uint32_t old_key = route->order_key ();
538
539                 if (order != old_key) {
540                         route->set_order_key (order);
541                         changed = true;
542                 }
543
544                 if ((Config->get_remote_model() == MixerOrdered) && !route->is_master() && !route->is_monitor()) {
545
546                         uint32_t new_rid = (visible ? rid : invisible_key--);
547
548                         if (new_rid != route->remote_control_id()) {
549                                 route->set_remote_control_id_explicit (new_rid);        
550                                 rid_change = true;
551                         }
552                         
553                         if (visible) {
554                                 rid++;
555                         }
556
557                 }
558
559                 ++order;
560         }
561
562         if (changed) {
563                 /* tell everyone that we changed the mixer sort keys */
564                 _session->sync_order_keys ();
565         }
566
567         if (rid_change) {
568                 /* tell the world that we changed the remote control IDs */
569                 _session->notify_remote_id_change ();
570         }
571 }
572
573 void
574 Mixer_UI::sync_treeview_from_order_keys ()
575 {
576         if (!_session || _session->deletion_in_progress()) {
577                 return;
578         }
579
580         DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync model from order keys.\n");
581
582         /* we could get here after either a change in the Mixer or Editor sort
583          * order, but either way, the mixer order keys reflect the intended
584          * order for the GUI, so reorder the treeview model to match it.
585          */
586
587         vector<int> neworder;
588         TreeModel::Children rows = track_model->children();
589         uint32_t old_order = 0;
590         bool changed = false;
591
592         if (rows.empty()) {
593                 return;
594         }
595
596         OrderKeySortedRoutes sorted_routes;
597
598         for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
599                 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
600                 sorted_routes.push_back (RoutePlusOrderKey (route, old_order, route->order_key ()));
601         }
602
603         SortByNewDisplayOrder cmp;
604
605         sort (sorted_routes.begin(), sorted_routes.end(), cmp);
606         neworder.assign (sorted_routes.size(), 0);
607
608         uint32_t n = 0;
609         
610         for (OrderKeySortedRoutes::iterator sr = sorted_routes.begin(); sr != sorted_routes.end(); ++sr, ++n) {
611
612                 neworder[n] = sr->old_display_order;
613
614                 if (sr->old_display_order != n) {
615                         changed = true;
616                 }
617
618                 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("MIXER change order for %1 from %2 to %3\n",
619                                                                sr->route->name(), sr->old_display_order, n));
620         }
621
622         if (changed) {
623                 Unwinder<bool> uw (ignore_reorder, true);
624                 track_model->reorder (neworder);
625         }
626
627         redisplay_track_list ();
628 }
629
630 void
631 Mixer_UI::follow_editor_selection ()
632 {
633         if (_following_editor_selection) {
634                 return;
635         }
636
637         _following_editor_selection = true;
638         _selection.block_routes_changed (true);
639         
640         TrackSelection& s (PublicEditor::instance().get_selection().tracks);
641
642         _selection.clear_routes ();
643
644         for (TrackViewList::iterator i = s.begin(); i != s.end(); ++i) {
645                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*i);
646                 if (rtav) {
647                         MixerStrip* ms = strip_by_route (rtav->route());
648                         if (ms) {
649                                 _selection.add (ms);
650                         }
651                 }
652         }
653
654         _following_editor_selection = false;
655         _selection.block_routes_changed (false);
656 }
657
658
659 MixerStrip*
660 Mixer_UI::strip_by_route (boost::shared_ptr<Route> r)
661 {
662         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
663                 if ((*i)->route() == r) {
664                         return (*i);
665                 }
666         }
667
668         return 0;
669 }
670
671 bool
672 Mixer_UI::strip_button_release_event (GdkEventButton *ev, MixerStrip *strip)
673 {
674         if (ev->button == 1) {
675                 if (_selection.selected (strip)) {
676                         /* primary-click: toggle selection state of strip */
677                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
678                                 _selection.remove (strip);
679                         } else if (_selection.routes.size() > 1) {
680                                 /* de-select others */
681                                 _selection.set (strip);
682                         }
683                 } else {
684                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
685                                 _selection.add (strip);
686                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::RangeSelectModifier)) {
687
688                                 if (!_selection.selected(strip)) {
689                                 
690                                         /* extend selection */
691                                         
692                                         vector<MixerStrip*> tmp;
693                                         bool accumulate = false;
694                                         bool found_another = false;
695                                         
696                                         tmp.push_back (strip);
697
698                                         for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
699                                                 if ((*i) == strip) {
700                                                         /* hit clicked strip, start accumulating till we hit the first 
701                                                            selected strip
702                                                         */
703                                                         if (accumulate) {
704                                                                 /* done */
705                                                                 break;
706                                                         } else {
707                                                                 accumulate = true;
708                                                         }
709                                                 } else if (_selection.selected (*i)) {
710                                                         /* hit selected strip. if currently accumulating others,
711                                                            we're done. if not accumulating others, start doing so.
712                                                         */
713                                                         found_another = true;
714                                                         if (accumulate) {
715                                                                 /* done */
716                                                                 break;
717                                                         } else {
718                                                                 accumulate = true;
719                                                         }
720                                                 } else {
721                                                         if (accumulate) {
722                                                                 tmp.push_back (*i);
723                                                         }
724                                                 }
725                                         }
726
727                                         if (found_another) {
728                                                 for (vector<MixerStrip*>::iterator i = tmp.begin(); i != tmp.end(); ++i) {
729                                                         _selection.add (*i);
730                                                 }
731                                         } else
732                                                 _selection.set (strip);  //user wants to start a range selection, but there aren't any others selected yet
733                                 }
734
735                         } else {
736                                 _selection.set (strip);
737                         }
738                 }
739         }
740
741         return true;
742 }
743
744 void
745 Mixer_UI::set_session (Session* sess)
746 {
747         SessionHandlePtr::set_session (sess);
748
749         if (_plugin_selector) {
750                 _plugin_selector->set_session (_session);
751         }
752
753         _group_tabs->set_session (sess);
754
755         if (!_session) {
756                 return;
757         }
758
759         XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
760         set_state (*node);
761
762         update_title ();
763
764         initial_track_display ();
765
766         _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_strips, this, _1), gui_context());
767         _session->route_group_added.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_route_group, this, _1), gui_context());
768         _session->route_group_removed.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
769         _session->route_groups_reordered.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
770         _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::parameter_changed, this, _1), gui_context());
771         _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::update_title, this), gui_context());
772         _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::update_title, this), gui_context());
773
774         Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::parameter_changed, this, _1), gui_context ());
775
776         route_groups_changed ();
777
778         if (_visible) {
779                 show_window();
780
781                 /* Bit of a hack; if we're here, we're opening the mixer because of our
782                    instant XML state having a show-mixer property.  Fix up the corresponding
783                    action state.
784                 */
785                 ActionManager::check_toggleaction ("<Actions>/Common/toggle-mixer");
786         }
787
788         start_updating ();
789 }
790
791 void
792 Mixer_UI::session_going_away ()
793 {
794         ENSURE_GUI_THREAD (*this, &Mixer_UI::session_going_away);
795
796         _in_group_rebuild_or_clear = true;
797         group_model->clear ();
798         _in_group_rebuild_or_clear = false;
799
800         _selection.clear ();
801         track_model->clear ();
802
803         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
804                 delete (*i);
805         }
806
807         if (_monitor_section) {
808                 _monitor_section->tearoff().hide_visible ();
809         }
810
811         strips.clear ();
812
813         stop_updating ();
814
815         SessionHandlePtr::session_going_away ();
816
817         _session = 0;
818         update_title ();
819 }
820
821 void
822 Mixer_UI::track_visibility_changed (std::string const & path)
823 {
824         if (_session && _session->deletion_in_progress()) {
825                 return;
826         }
827
828         TreeIter iter;
829
830         if ((iter = track_model->get_iter (path))) {
831                 MixerStrip* strip = (*iter)[track_columns.strip];
832                 if (strip) {
833                         bool visible = (*iter)[track_columns.visible];
834
835                         if (strip->set_marked_for_display (!visible)) {
836                                 update_track_visibility ();
837                         }
838                 }
839         }
840 }
841
842 void
843 Mixer_UI::update_track_visibility ()
844 {
845         TreeModel::Children rows = track_model->children();
846         TreeModel::Children::iterator i;
847
848         {
849                 Unwinder<bool> uw (no_track_list_redisplay, true);
850                 
851                 for (i = rows.begin(); i != rows.end(); ++i) {
852                         MixerStrip *strip = (*i)[track_columns.strip];
853                         (*i)[track_columns.visible] = strip->marked_for_display ();
854                 }
855                 
856                 /* force route order keys catch up with visibility changes
857                  */
858                 
859                 sync_order_keys_from_treeview ();
860         }
861
862         redisplay_track_list ();
863 }
864
865 void
866 Mixer_UI::show_strip (MixerStrip* ms)
867 {
868         TreeModel::Children rows = track_model->children();
869         TreeModel::Children::iterator i;
870
871         for (i = rows.begin(); i != rows.end(); ++i) {
872
873                 MixerStrip* strip = (*i)[track_columns.strip];
874                 if (strip == ms) {
875                         (*i)[track_columns.visible] = true;
876                         redisplay_track_list ();
877                         break;
878                 }
879         }
880 }
881
882 void
883 Mixer_UI::hide_strip (MixerStrip* ms)
884 {
885         TreeModel::Children rows = track_model->children();
886         TreeModel::Children::iterator i;
887
888         for (i = rows.begin(); i != rows.end(); ++i) {
889
890                 MixerStrip* strip = (*i)[track_columns.strip];
891                 if (strip == ms) {
892                         (*i)[track_columns.visible] = false;
893                         redisplay_track_list ();
894                         break;
895                 }
896         }
897 }
898
899 gint
900 Mixer_UI::start_updating ()
901 {
902     fast_screen_update_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &Mixer_UI::fast_update_strips));
903     return 0;
904 }
905
906 gint
907 Mixer_UI::stop_updating ()
908 {
909     fast_screen_update_connection.disconnect();
910     return 0;
911 }
912
913 void
914 Mixer_UI::fast_update_strips ()
915 {
916         if (is_mapped () && _session) {
917                 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
918                         (*i)->fast_update ();
919                 }
920         }
921 }
922
923 void
924 Mixer_UI::set_all_strips_visibility (bool yn)
925 {
926         TreeModel::Children rows = track_model->children();
927         TreeModel::Children::iterator i;
928
929         {
930                 Unwinder<bool> uw (no_track_list_redisplay, true);
931                 
932                 for (i = rows.begin(); i != rows.end(); ++i) {
933                         
934                         TreeModel::Row row = (*i);
935                         MixerStrip* strip = row[track_columns.strip];
936                         
937                         if (strip == 0) {
938                                 continue;
939                         }
940                         
941                         if (strip->route()->is_master() || strip->route()->is_monitor()) {
942                                 continue;
943                         }
944                         
945                         (*i)[track_columns.visible] = yn;
946                 }
947         }
948
949         redisplay_track_list ();
950 }
951
952
953 void
954 Mixer_UI::set_all_audio_visibility (int tracks, bool yn)
955 {
956         TreeModel::Children rows = track_model->children();
957         TreeModel::Children::iterator i;
958
959         {
960                 Unwinder<bool> uw (no_track_list_redisplay, true);
961                 
962                 for (i = rows.begin(); i != rows.end(); ++i) {
963                         TreeModel::Row row = (*i);
964                         MixerStrip* strip = row[track_columns.strip];
965                         
966                         if (strip == 0) {
967                                 continue;
968                         }
969                         
970                         if (strip->route()->is_master() || strip->route()->is_monitor()) {
971                                 continue;
972                         }
973                         
974                         boost::shared_ptr<AudioTrack> at = strip->audio_track();
975                         
976                         switch (tracks) {
977                         case 0:
978                                 (*i)[track_columns.visible] = yn;
979                                 break;
980                                 
981                         case 1:
982                                 if (at) { /* track */
983                                         (*i)[track_columns.visible] = yn;
984                                 }
985                                 break;
986                                 
987                         case 2:
988                                 if (!at) { /* bus */
989                                         (*i)[track_columns.visible] = yn;
990                                 }
991                                 break;
992                         }
993                 }
994         }
995
996         redisplay_track_list ();
997 }
998
999 void
1000 Mixer_UI::hide_all_routes ()
1001 {
1002         set_all_strips_visibility (false);
1003 }
1004
1005 void
1006 Mixer_UI::show_all_routes ()
1007 {
1008         set_all_strips_visibility (true);
1009 }
1010
1011 void
1012 Mixer_UI::show_all_audiobus ()
1013 {
1014         set_all_audio_visibility (2, true);
1015 }
1016 void
1017 Mixer_UI::hide_all_audiobus ()
1018 {
1019         set_all_audio_visibility (2, false);
1020 }
1021
1022 void
1023 Mixer_UI::show_all_audiotracks()
1024 {
1025         set_all_audio_visibility (1, true);
1026 }
1027 void
1028 Mixer_UI::hide_all_audiotracks ()
1029 {
1030         set_all_audio_visibility (1, false);
1031 }
1032
1033 void
1034 Mixer_UI::track_list_reorder (const TreeModel::Path&, const TreeModel::iterator&, int* /*new_order*/)
1035 {
1036         DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview reordered\n");
1037         sync_order_keys_from_treeview ();
1038 }
1039
1040 void
1041 Mixer_UI::track_list_delete (const Gtk::TreeModel::Path&)
1042 {
1043         /* this happens as the second step of a DnD within the treeview as well
1044            as when a row/route is actually deleted.
1045            
1046            if it was a deletion then we have to force a redisplay because
1047            order keys may not have changed.
1048         */
1049
1050         DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview row deleted\n");
1051         sync_order_keys_from_treeview ();
1052
1053         if (_route_deletion_in_progress) {
1054                 redisplay_track_list ();
1055         }
1056 }
1057
1058 void
1059 Mixer_UI::redisplay_track_list ()
1060 {
1061         TreeModel::Children rows = track_model->children();
1062         TreeModel::Children::iterator i;
1063         
1064         if (no_track_list_redisplay) {
1065                 return;
1066         }
1067
1068         for (i = rows.begin(); i != rows.end(); ++i) {
1069
1070                 MixerStrip* strip = (*i)[track_columns.strip];
1071
1072                 if (strip == 0) {
1073                         /* we're in the middle of changing a row, don't worry */
1074                         continue;
1075                 }
1076
1077                 bool const visible = (*i)[track_columns.visible];
1078
1079                 if (visible) {
1080                         strip->set_gui_property ("visible", true);
1081
1082                         if (strip->packed()) {
1083
1084                                 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1085                                         out_packer.reorder_child (*strip, -1);
1086
1087                                 } else {
1088                                         strip_packer.reorder_child (*strip, -1); /* put at end */
1089                                 }
1090
1091                         } else {
1092
1093                                 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1094                                         out_packer.pack_start (*strip, false, false);
1095                                 } else {
1096                                         strip_packer.pack_start (*strip, false, false);
1097                                 }
1098                                 strip->set_packed (true);
1099                         }
1100
1101                 } else {
1102
1103                         strip->set_gui_property ("visible", false);
1104
1105                         if (strip->route()->is_master() || strip->route()->is_monitor()) {
1106                                 /* do nothing, these cannot be hidden */
1107                         } else {
1108                                 if (strip->packed()) {
1109                                         strip_packer.remove (*strip);
1110                                         strip->set_packed (false);
1111                                 }
1112                         }
1113                 }
1114         }
1115
1116         _group_tabs->set_dirty ();
1117 }
1118
1119 void
1120 Mixer_UI::strip_width_changed ()
1121 {
1122         _group_tabs->set_dirty ();
1123
1124 #ifdef GTKOSX
1125         TreeModel::Children rows = track_model->children();
1126         TreeModel::Children::iterator i;
1127         long order;
1128
1129         for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
1130                 MixerStrip* strip = (*i)[track_columns.strip];
1131
1132                 if (strip == 0) {
1133                         continue;
1134                 }
1135
1136                 bool visible = (*i)[track_columns.visible];
1137
1138                 if (visible) {
1139                         strip->queue_draw();
1140                 }
1141         }
1142 #endif
1143
1144 }
1145
1146 void
1147 Mixer_UI::initial_track_display ()
1148 {
1149         boost::shared_ptr<RouteList> routes = _session->get_routes();
1150         RouteList copy (*routes);
1151         ARDOUR::SignalOrderRouteSorter sorter;
1152
1153         copy.sort (sorter);
1154
1155         {
1156                 Unwinder<bool> uw1 (no_track_list_redisplay, true);
1157                 Unwinder<bool> uw2 (ignore_reorder, true);
1158
1159                 track_model->clear ();
1160                 add_strips (copy);
1161         }
1162         
1163         _session->sync_order_keys ();
1164
1165         redisplay_track_list ();
1166 }
1167
1168 void
1169 Mixer_UI::show_track_list_menu ()
1170 {
1171         if (track_menu == 0) {
1172                 build_track_menu ();
1173         }
1174
1175         track_menu->popup (1, gtk_get_current_event_time());
1176 }
1177
1178 bool
1179 Mixer_UI::track_display_button_press (GdkEventButton* ev)
1180 {
1181         if (Keyboard::is_context_menu_event (ev)) {
1182                 show_track_list_menu ();
1183                 return true;
1184         }
1185
1186         return false;
1187 }
1188
1189 void
1190 Mixer_UI::build_track_menu ()
1191 {
1192         using namespace Menu_Helpers;
1193         using namespace Gtk;
1194
1195         track_menu = new Menu;
1196         track_menu->set_name ("ArdourContextMenu");
1197         MenuList& items = track_menu->items();
1198
1199         items.push_back (MenuElem (_("Show All"), sigc::mem_fun(*this, &Mixer_UI::show_all_routes)));
1200         items.push_back (MenuElem (_("Hide All"), sigc::mem_fun(*this, &Mixer_UI::hide_all_routes)));
1201         items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
1202         items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
1203         items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus)));
1204         items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
1205
1206 }
1207
1208 void
1209 Mixer_UI::strip_property_changed (const PropertyChange& what_changed, MixerStrip* mx)
1210 {
1211         if (!what_changed.contains (ARDOUR::Properties::name)) {
1212                 return;
1213         }
1214
1215         ENSURE_GUI_THREAD (*this, &Mixer_UI::strip_name_changed, what_changed, mx)
1216
1217         TreeModel::Children rows = track_model->children();
1218         TreeModel::Children::iterator i;
1219
1220         for (i = rows.begin(); i != rows.end(); ++i) {
1221                 if ((*i)[track_columns.strip] == mx) {
1222                         (*i)[track_columns.text] = mx->route()->name();
1223                         return;
1224                 }
1225         }
1226
1227         error << _("track display list item for renamed strip not found!") << endmsg;
1228 }
1229
1230 bool
1231 Mixer_UI::group_display_button_press (GdkEventButton* ev)
1232 {
1233         TreeModel::Path path;
1234         TreeViewColumn* column;
1235         int cellx;
1236         int celly;
1237
1238         if (!group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
1239                 _group_tabs->get_menu(0)->popup (1, ev->time);
1240                 return true;
1241         }
1242
1243         TreeIter iter = group_model->get_iter (path);
1244         if (!iter) {
1245                 _group_tabs->get_menu(0)->popup (1, ev->time);
1246                 return true;
1247         }
1248
1249         RouteGroup* group = (*iter)[group_columns.group];
1250
1251         if (Keyboard::is_context_menu_event (ev)) {
1252                 _group_tabs->get_menu(group)->popup (1, ev->time);
1253                 return true;
1254         }
1255
1256         switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
1257         case 0:
1258                 if (Keyboard::is_edit_event (ev)) {
1259                         if (group) {
1260                                 // edit_route_group (group);
1261 #ifdef GTKOSX
1262                                 group_display.queue_draw();
1263 #endif
1264                                 return true;
1265                         }
1266                 }
1267                 break;
1268
1269         case 1:
1270         {
1271                 bool visible = (*iter)[group_columns.visible];
1272                 (*iter)[group_columns.visible] = !visible;
1273 #ifdef GTKOSX
1274                 group_display.queue_draw();
1275 #endif
1276                 return true;
1277         }
1278
1279         default:
1280                 break;
1281         }
1282
1283         return false;
1284  }
1285
1286 void
1287 Mixer_UI::activate_all_route_groups ()
1288 {
1289         _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), true));
1290 }
1291
1292 void
1293 Mixer_UI::disable_all_route_groups ()
1294 {
1295         _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), false));
1296 }
1297
1298 void
1299 Mixer_UI::route_groups_changed ()
1300 {
1301         ENSURE_GUI_THREAD (*this, &Mixer_UI::route_groups_changed);
1302
1303         _in_group_rebuild_or_clear = true;
1304
1305         /* just rebuild the while thing */
1306
1307         group_model->clear ();
1308
1309 #if 0
1310         /* this is currently not used,
1311          * Mixer_UI::group_display_button_press() has a case for it,
1312          * and a commented edit_route_group() but that's n/a since 2011.
1313          *
1314          * This code is left as reminder that
1315          * row[group_columns.group] = 0 has special meaning.
1316          */
1317         {
1318                 TreeModel::Row row;
1319                 row = *(group_model->append());
1320                 row[group_columns.visible] = true;
1321                 row[group_columns.text] = (_("-all-"));
1322                 row[group_columns.group] = 0;
1323         }
1324 #endif
1325
1326         _session->foreach_route_group (sigc::mem_fun (*this, &Mixer_UI::add_route_group));
1327
1328         _group_tabs->set_dirty ();
1329         _in_group_rebuild_or_clear = false;
1330 }
1331
1332 void
1333 Mixer_UI::new_route_group ()
1334 {
1335         RouteList rl;
1336
1337         _group_tabs->run_new_group_dialog (rl);
1338 }
1339
1340 void
1341 Mixer_UI::remove_selected_route_group ()
1342 {
1343         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1344         TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1345
1346         if (rows.empty()) {
1347                 return;
1348         }
1349
1350         TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1351         TreeIter iter;
1352
1353         /* selection mode is single, so rows.begin() is it */
1354
1355         if ((iter = group_model->get_iter (*i))) {
1356
1357                 RouteGroup* rg = (*iter)[group_columns.group];
1358
1359                 if (rg) {
1360                         _session->remove_route_group (*rg);
1361                 }
1362         }
1363 }
1364
1365 void
1366 Mixer_UI::route_group_property_changed (RouteGroup* group, const PropertyChange& change)
1367 {
1368         if (in_group_row_change) {
1369                 return;
1370         }
1371
1372         /* force an update of any mixer strips that are using this group,
1373            otherwise mix group names don't change in mixer strips
1374         */
1375
1376         for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1377                 if ((*i)->route_group() == group) {
1378                         (*i)->route_group_changed();
1379                 }
1380         }
1381
1382         TreeModel::iterator i;
1383         TreeModel::Children rows = group_model->children();
1384         Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1385
1386         in_group_row_change = true;
1387
1388         for (i = rows.begin(); i != rows.end(); ++i) {
1389                 if ((*i)[group_columns.group] == group) {
1390                         (*i)[group_columns.visible] = !group->is_hidden ();
1391                         (*i)[group_columns.text] = group->name ();
1392                         break;
1393                 }
1394         }
1395
1396         in_group_row_change = false;
1397
1398         if (change.contains (Properties::name)) {
1399                 _group_tabs->set_dirty ();
1400         }
1401
1402         for (list<MixerStrip*>::iterator j = strips.begin(); j != strips.end(); ++j) {
1403                 if ((*j)->route_group() == group) {
1404                         if (group->is_hidden ()) {
1405                                 hide_strip (*j);
1406                         } else {
1407                                 show_strip (*j);
1408                         }
1409                 }
1410         }
1411 }
1412
1413 void
1414 Mixer_UI::route_group_name_edit (const std::string& path, const std::string& new_text)
1415 {
1416         RouteGroup* group;
1417         TreeIter iter;
1418
1419         if ((iter = group_model->get_iter (path))) {
1420
1421                 if ((group = (*iter)[group_columns.group]) == 0) {
1422                         return;
1423                 }
1424
1425                 if (new_text != group->name()) {
1426                         group->set_name (new_text);
1427                 }
1428         }
1429 }
1430
1431 void
1432 Mixer_UI::route_group_row_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator& iter)
1433 {
1434         RouteGroup* group;
1435
1436         if (in_group_row_change) {
1437                 return;
1438         }
1439
1440         if ((group = (*iter)[group_columns.group]) == 0) {
1441                 return;
1442         }
1443
1444         std::string name = (*iter)[group_columns.text];
1445
1446         if (name != group->name()) {
1447                 group->set_name (name);
1448         }
1449
1450         bool hidden = !(*iter)[group_columns.visible];
1451
1452         if (hidden != group->is_hidden ()) {
1453                 group->set_hidden (hidden, this);
1454         }
1455 }
1456
1457 /** Called when a group model row is deleted, but also when the model is
1458  *  reordered by a user drag-and-drop; the latter is what we are
1459  *  interested in here.
1460  */
1461 void
1462 Mixer_UI::route_group_row_deleted (Gtk::TreeModel::Path const &)
1463 {
1464         if (_in_group_rebuild_or_clear) {
1465                 return;
1466         }
1467
1468         /* Re-write the session's route group list so that the new order is preserved */
1469
1470         list<RouteGroup*> new_list;
1471
1472         Gtk::TreeModel::Children children = group_model->children();
1473         for (Gtk::TreeModel::Children::iterator i = children.begin(); i != children.end(); ++i) {
1474                 RouteGroup* g = (*i)[group_columns.group];
1475                 if (g) {
1476                         new_list.push_back (g);
1477                 }
1478         }
1479
1480         _session->reorder_route_groups (new_list);
1481 }
1482
1483
1484 void
1485 Mixer_UI::add_route_group (RouteGroup* group)
1486 {
1487         ENSURE_GUI_THREAD (*this, &Mixer_UI::add_route_group, group)
1488         bool focus = false;
1489
1490         in_group_row_change = true;
1491
1492         TreeModel::Row row = *(group_model->append());
1493         row[group_columns.visible] = !group->is_hidden ();
1494         row[group_columns.group] = group;
1495         if (!group->name().empty()) {
1496                 row[group_columns.text] = group->name();
1497         } else {
1498                 row[group_columns.text] = _("unnamed");
1499                 focus = true;
1500         }
1501
1502         group->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::route_group_property_changed, this, group, _1), gui_context());
1503
1504         if (focus) {
1505                 TreeViewColumn* col = group_display.get_column (0);
1506                 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
1507                 group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true);
1508         }
1509
1510         _group_tabs->set_dirty ();
1511
1512         in_group_row_change = false;
1513 }
1514
1515 bool
1516 Mixer_UI::strip_scroller_button_release (GdkEventButton* ev)
1517 {
1518         using namespace Menu_Helpers;
1519
1520         if (Keyboard::is_context_menu_event (ev)) {
1521                 ARDOUR_UI::instance()->add_route (this);
1522                 return true;
1523         }
1524
1525         return false;
1526 }
1527
1528 void
1529 Mixer_UI::set_strip_width (Width w, bool save)
1530 {
1531         _strip_width = w;
1532
1533         for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1534                 (*i)->set_width_enum (w, save ? (*i)->width_owner() : this);
1535         }
1536 }
1537
1538 void
1539 Mixer_UI::set_window_pos_and_size ()
1540 {
1541         resize (m_width, m_height);
1542         move (m_root_x, m_root_y);
1543 }
1544
1545         void
1546 Mixer_UI::get_window_pos_and_size ()
1547 {
1548         get_position(m_root_x, m_root_y);
1549         get_size(m_width, m_height);
1550 }
1551
1552 int
1553 Mixer_UI::set_state (const XMLNode& node)
1554 {
1555         const XMLProperty* prop;
1556         XMLNode* geometry;
1557
1558         m_width = default_width;
1559         m_height = default_height;
1560         m_root_x = 1;
1561         m_root_y = 1;
1562
1563         if ((geometry = find_named_node (node, "geometry")) != 0) {
1564
1565                 XMLProperty* prop;
1566
1567                 if ((prop = geometry->property("x_size")) == 0) {
1568                         prop = geometry->property ("x-size");
1569                 }
1570                 if (prop) {
1571                         m_width = atoi(prop->value());
1572                 }
1573                 if ((prop = geometry->property("y_size")) == 0) {
1574                         prop = geometry->property ("y-size");
1575                 }
1576                 if (prop) {
1577                         m_height = atoi(prop->value());
1578                 }
1579
1580                 if ((prop = geometry->property ("x_pos")) == 0) {
1581                         prop = geometry->property ("x-pos");
1582                 }
1583                 if (prop) {
1584                         m_root_x = atoi (prop->value());
1585
1586                 }
1587                 if ((prop = geometry->property ("y_pos")) == 0) {
1588                         prop = geometry->property ("y-pos");
1589                 }
1590                 if (prop) {
1591                         m_root_y = atoi (prop->value());
1592                 }
1593         }
1594
1595         set_window_pos_and_size ();
1596
1597         if ((prop = node.property ("narrow-strips"))) {
1598                 if (string_is_affirmative (prop->value())) {
1599                         set_strip_width (Narrow);
1600                 } else {
1601                         set_strip_width (Wide);
1602                 }
1603         }
1604
1605         if ((prop = node.property ("show-mixer"))) {
1606                 if (string_is_affirmative (prop->value())) {
1607                        _visible = true;
1608                 }
1609         }
1610
1611         if ((prop = node.property ("maximised"))) {
1612                 bool yn = string_is_affirmative (prop->value());
1613                 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalMixer"));
1614                 assert (act);
1615                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1616                 bool fs = tact && tact->get_active();
1617                 if (yn ^ fs) {
1618                         ActionManager::do_action ("Common",
1619                                         "ToggleMaximalMixer");
1620                 }
1621         }
1622
1623
1624         return 0;
1625 }
1626
1627 XMLNode&
1628 Mixer_UI::get_state (void)
1629 {
1630         XMLNode* node = new XMLNode ("Mixer");
1631
1632         if (is_realized()) {
1633                 Glib::RefPtr<Gdk::Window> win = get_window();
1634
1635                 get_window_pos_and_size ();
1636
1637                 XMLNode* geometry = new XMLNode ("geometry");
1638                 char buf[32];
1639                 snprintf(buf, sizeof(buf), "%d", m_width);
1640                 geometry->add_property(X_("x_size"), string(buf));
1641                 snprintf(buf, sizeof(buf), "%d", m_height);
1642                 geometry->add_property(X_("y_size"), string(buf));
1643                 snprintf(buf, sizeof(buf), "%d", m_root_x);
1644                 geometry->add_property(X_("x_pos"), string(buf));
1645                 snprintf(buf, sizeof(buf), "%d", m_root_y);
1646                 geometry->add_property(X_("y_pos"), string(buf));
1647
1648                 // written only for compatibility, they are not used.
1649                 snprintf(buf, sizeof(buf), "%d", 0);
1650                 geometry->add_property(X_("x_off"), string(buf));
1651                 snprintf(buf, sizeof(buf), "%d", 0);
1652                 geometry->add_property(X_("y_off"), string(buf));
1653
1654                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&rhs_pane1)->gobj()));
1655                 geometry->add_property(X_("mixer_rhs_pane1_pos"), string(buf));
1656                 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&list_hpane)->gobj()));
1657                 geometry->add_property(X_("mixer_list_hpane_pos"), string(buf));
1658
1659                 node->add_child_nocopy (*geometry);
1660         }
1661
1662         node->add_property ("narrow-strips", _strip_width == Narrow ? "yes" : "no");
1663
1664         node->add_property ("show-mixer", _visible ? "yes" : "no");
1665
1666         node->add_property ("maximised", _maximised ? "yes" : "no");
1667
1668         return *node;
1669 }
1670
1671
1672 void
1673 Mixer_UI::pane_allocation_handler (Allocation&, Gtk::Paned* which)
1674 {
1675         int pos;
1676         XMLProperty* prop = 0;
1677         char buf[32];
1678         XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
1679         XMLNode* geometry;
1680         int height;
1681         static int32_t done[3] = { 0, 0, 0 };
1682
1683         height = default_height;
1684
1685         if ((geometry = find_named_node (*node, "geometry")) != 0) {
1686
1687                 if ((prop = geometry->property ("y_size")) == 0) {
1688                         prop = geometry->property ("y-size");
1689                 }
1690                 if (prop) {
1691                         height = atoi (prop->value());
1692                 }
1693         }
1694
1695         if (which == static_cast<Gtk::Paned*> (&rhs_pane1)) {
1696
1697                 if (done[0]) {
1698                         return;
1699                 }
1700
1701                 if (!geometry || (prop = geometry->property("mixer-rhs-pane1-pos")) == 0) {
1702                         pos = height / 3;
1703                         snprintf (buf, sizeof(buf), "%d", pos);
1704                 } else {
1705                         pos = atoi (prop->value());
1706                 }
1707
1708                 if ((done[0] = GTK_WIDGET(rhs_pane1.gobj())->allocation.height > pos)) {
1709                         rhs_pane1.set_position (pos);
1710                 }
1711
1712         } else if (which == static_cast<Gtk::Paned*> (&list_hpane)) {
1713
1714                 if (done[2]) {
1715                         return;
1716                 }
1717
1718                 if (!geometry || (prop = geometry->property("mixer-list-hpane-pos")) == 0) {
1719                         pos = 75;
1720                         snprintf (buf, sizeof(buf), "%d", pos);
1721                 } else {
1722                         pos = atoi (prop->value());
1723                 }
1724
1725                 if ((done[2] = GTK_WIDGET(list_hpane.gobj())->allocation.width > pos)) {
1726                         list_hpane.set_position (pos);
1727                 }
1728         }
1729 }
1730 void
1731 Mixer_UI::scroll_left ()
1732 {
1733         if (!scroller.get_hscrollbar()) return;
1734         Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1735         /* stupid GTK: can't rely on clamping across versions */
1736         scroller.get_hscrollbar()->set_value (max (adj->get_lower(), adj->get_value() - adj->get_step_increment()));
1737 }
1738
1739 void
1740 Mixer_UI::scroll_right ()
1741 {
1742         if (!scroller.get_hscrollbar()) return;
1743         Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
1744         /* stupid GTK: can't rely on clamping across versions */
1745         scroller.get_hscrollbar()->set_value (min (adj->get_upper(), adj->get_value() + adj->get_step_increment()));
1746 }
1747
1748 bool
1749 Mixer_UI::on_key_press_event (GdkEventKey* ev)
1750 {
1751         /* focus widget gets first shot, then bindings, otherwise
1752            forward to main window
1753         */
1754
1755         if (gtk_window_propagate_key_event (GTK_WINDOW(gobj()), ev)) {
1756                 return true;
1757         }
1758
1759         KeyboardKey k (ev->state, ev->keyval);
1760
1761         if (bindings.activate (k, Bindings::Press)) {
1762                 return true;
1763         }
1764
1765         return forward_key_press (ev);
1766 }
1767
1768 bool
1769 Mixer_UI::on_key_release_event (GdkEventKey* ev)
1770 {
1771         if (gtk_window_propagate_key_event (GTK_WINDOW(gobj()), ev)) {
1772                 return true;
1773         }
1774
1775         KeyboardKey k (ev->state, ev->keyval);
1776         
1777         if (bindings.activate (k, Bindings::Release)) {
1778                 return true;
1779         }
1780
1781         /* don't forward releases */
1782
1783         return true;
1784 }
1785
1786 bool
1787 Mixer_UI::on_scroll_event (GdkEventScroll* ev)
1788 {
1789         switch (ev->direction) {
1790         case GDK_SCROLL_LEFT:
1791                 scroll_left ();
1792                 return true;
1793         case GDK_SCROLL_UP:
1794                 if (ev->state & Keyboard::TertiaryModifier) {
1795                         scroll_left ();
1796                         return true;
1797                 }
1798                 return false;
1799
1800         case GDK_SCROLL_RIGHT:
1801                 scroll_right ();
1802                 return true;
1803
1804         case GDK_SCROLL_DOWN:
1805                 if (ev->state & Keyboard::TertiaryModifier) {
1806                         scroll_right ();
1807                         return true;
1808                 }
1809                 return false;
1810         }
1811
1812         return false;
1813 }
1814
1815
1816 void
1817 Mixer_UI::parameter_changed (string const & p)
1818 {
1819         if (p == "show-group-tabs") {
1820                 bool const s = _session->config.get_show_group_tabs ();
1821                 if (s) {
1822                         _group_tabs->show ();
1823                 } else {
1824                         _group_tabs->hide ();
1825                 }
1826         } else if (p == "default-narrow_ms") {
1827                 bool const s = ARDOUR_UI::config()->get_default_narrow_ms ();
1828                 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1829                         (*i)->set_width_enum (s ? Narrow : Wide, this);
1830                 }
1831         } else if (p == "remote-model") {
1832                 reset_remote_control_ids ();
1833         }
1834 }
1835
1836 void
1837 Mixer_UI::set_route_group_activation (RouteGroup* g, bool a)
1838 {
1839         g->set_active (a, this);
1840 }
1841
1842 PluginSelector*
1843 Mixer_UI::plugin_selector()
1844 {
1845 #ifdef DEFER_PLUGIN_SELECTOR_LOAD
1846         if (!_plugin_selector)
1847                 _plugin_selector = new PluginSelector (PluginManager::instance());
1848 #endif
1849
1850         return _plugin_selector;
1851 }
1852
1853 void
1854 Mixer_UI::setup_track_display ()
1855 {
1856         track_model = ListStore::create (track_columns);
1857         track_display.set_model (track_model);
1858         track_display.append_column (_("Strips"), track_columns.text);
1859         track_display.append_column (_("Show"), track_columns.visible);
1860         track_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
1861         track_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
1862         track_display.get_column (0)->set_expand(true);
1863         track_display.get_column (1)->set_expand(false);
1864         track_display.get_column (0)->set_sizing (Gtk::TREE_VIEW_COLUMN_FIXED);
1865         track_display.set_name (X_("EditGroupList"));
1866         track_display.get_selection()->set_mode (Gtk::SELECTION_NONE);
1867         track_display.set_reorderable (true);
1868         track_display.set_headers_visible (true);
1869
1870         track_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_delete));
1871         track_model->signal_rows_reordered().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_reorder));
1872
1873         CellRendererToggle* track_list_visible_cell = dynamic_cast<CellRendererToggle*>(track_display.get_column_cell_renderer (1));
1874         track_list_visible_cell->property_activatable() = true;
1875         track_list_visible_cell->property_radio() = false;
1876         track_list_visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &Mixer_UI::track_visibility_changed));
1877
1878         track_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::track_display_button_press), false);
1879
1880         track_display_scroller.add (track_display);
1881         track_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1882
1883         VBox* v = manage (new VBox);
1884         v->show ();
1885         v->pack_start (track_display_scroller, true, true);
1886
1887         Button* b = manage (new Button);
1888         b->show ();
1889         Widget* w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
1890         w->show ();
1891         b->add (*w);
1892
1893         b->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus));
1894
1895         v->pack_start (*b, false, false);
1896
1897         track_display_frame.set_name("BaseFrame");
1898         track_display_frame.set_shadow_type (Gtk::SHADOW_IN);
1899         track_display_frame.add (*v);
1900
1901         track_display_scroller.show();
1902         track_display_frame.show();
1903         track_display.show();
1904 }
1905
1906 void
1907 Mixer_UI::new_track_or_bus ()
1908 {
1909         ARDOUR_UI::instance()->add_route (this);
1910 }
1911
1912
1913 void
1914 Mixer_UI::update_title ()
1915 {
1916         if (_session) {
1917                 string n;
1918                 
1919                 if (_session->snap_name() != _session->name()) {
1920                         n = _session->snap_name ();
1921                 } else {
1922                         n = _session->name ();
1923                 }
1924
1925                 if (_session->dirty ()) {
1926                         n = "*" + n;
1927                 }
1928                 
1929                 WindowTitle title (n);
1930                 title += S_("Window|Mixer");
1931                 title += Glib::get_application_name ();
1932                 set_title (title.get_string());
1933
1934         } else {
1935                 
1936                 WindowTitle title (S_("Window|Mixer"));
1937                 title += Glib::get_application_name ();
1938                 set_title (title.get_string());
1939         }
1940 }
1941
1942 MixerStrip*
1943 Mixer_UI::strip_by_x (int x)
1944 {
1945         for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1946                 int x1, x2, y;
1947
1948                 (*i)->translate_coordinates (*this, 0, 0, x1, y);
1949                 x2 = x1 + (*i)->get_width();
1950
1951                 if (x >= x1 && x <= x2) {
1952                         return (*i);
1953                 }
1954         }
1955
1956         return 0;
1957 }
1958
1959 void
1960 Mixer_UI::set_route_targets_for_operation ()
1961 {
1962         _route_targets.clear ();
1963
1964         if (!_selection.empty()) {
1965                 _route_targets = _selection.routes;
1966                 return;
1967         }
1968
1969 //  removed "implicit" selections of strips, after discussion on IRC
1970
1971 }
1972
1973 void
1974 Mixer_UI::monitor_section_going_away ()
1975 {
1976         if (_monitor_section) {
1977                 out_packer.remove (_monitor_section->tearoff());
1978                 _monitor_section->set_session (0);
1979         }
1980 }
1981
1982 void
1983 Mixer_UI::toggle_midi_input_active (bool flip_others)
1984 {
1985         boost::shared_ptr<RouteList> rl (new RouteList);
1986         bool onoff = false;
1987
1988         set_route_targets_for_operation ();
1989
1990         for (RouteUISelection::iterator r = _route_targets.begin(); r != _route_targets.end(); ++r) {
1991                 boost::shared_ptr<MidiTrack> mt = (*r)->midi_track();
1992
1993                 if (mt) {
1994                         rl->push_back ((*r)->route());
1995                         onoff = !mt->input_active();
1996                 }
1997         }
1998         
1999         _session->set_exclusive_input_active (rl, onoff, flip_others);
2000 }
2001
2002 void
2003 Mixer_UI::maximise_mixer_space ()
2004 {
2005         if (_maximised) {
2006                 return;
2007         }
2008
2009         fullscreen ();
2010
2011         _maximised = true;
2012 }
2013
2014 void
2015 Mixer_UI::restore_mixer_space ()
2016 {
2017         if (!_maximised) {
2018                 return;
2019         }
2020
2021         unfullscreen();
2022
2023         _maximised = false;
2024 }