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