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