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