2 Copyright (C) 2000-2004 Paul Davis
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.
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.
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.
21 #include "gtk2ardour-config.h"
26 #include <sigc++/bind.h>
28 #include <gtkmm/accelmap.h>
30 #include "pbd/convert.h"
31 #include "pbd/stacktrace.h"
32 #include "pbd/unwind.h"
34 #include <glibmm/threads.h>
36 #include <gtkmm2ext/gtk_ui.h>
37 #include <gtkmm2ext/keyboard.h>
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/tearoff.h>
40 #include <gtkmm2ext/window_title.h>
41 #include <gtkmm2ext/doi.h>
43 #include "ardour/amp.h"
44 #include "ardour/debug.h"
45 #include "ardour/audio_track.h"
46 #include "ardour/midi_track.h"
47 #include "ardour/plugin_manager.h"
48 #include "ardour/route_group.h"
49 #include "ardour/session.h"
50 #include "ardour/vca.h"
51 #include "ardour/vca_manager.h"
55 #include "mixer_strip.h"
56 #include "monitor_section.h"
57 #include "plugin_selector.h"
58 #include "public_editor.h"
59 #include "ardour_ui.h"
62 #include "route_sorter.h"
64 #include "gui_thread.h"
65 #include "mixer_group_tabs.h"
67 #include "ui_config.h"
68 #include "vca_master_strip.h"
72 using namespace ARDOUR;
73 using namespace ARDOUR_UI_UTILS;
77 using namespace Gtkmm2ext;
83 Mixer_UI* Mixer_UI::_instance = 0;
89 _instance = new Mixer_UI;
96 : Tabbable (_content, _("Mixer"))
97 , no_track_list_redisplay (false)
98 , in_group_row_change (false)
100 , _monitor_section (0)
101 , _plugin_selector (0)
102 , _strip_width (UIConfiguration::instance().get_default_narrow_ms() ? Narrow : Wide)
103 , ignore_reorder (false)
104 , _in_group_rebuild_or_clear (false)
105 , _route_deletion_in_progress (false)
106 , _following_editor_selection (false)
108 , _show_mixer_list (true)
110 Stripable::PresentationInfoChange.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::sync_treeview_from_presentation_info, this), gui_context());
112 /* bindings was already set in MixerActor constructor */
114 _content.set_data ("ardour-bindings", bindings);
116 scroller.set_can_default (true);
117 // set_default (scroller);
119 scroller_base.set_flags (Gtk::CAN_FOCUS);
120 scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
121 scroller_base.set_name ("MixerWindow");
122 scroller_base.signal_button_release_event().connect (sigc::mem_fun(*this, &Mixer_UI::strip_scroller_button_release));
124 /* set up drag-n-drop */
125 vector<TargetEntry> target_table;
126 target_table.push_back (TargetEntry ("PluginFavoritePtr"));
127 scroller_base.drag_dest_set (target_table);
128 scroller_base.signal_drag_data_received().connect (sigc::mem_fun(*this, &Mixer_UI::scroller_drag_data_received));
130 // add as last item of strip packer
131 strip_packer.pack_end (scroller_base, true, true);
133 _group_tabs = new MixerGroupTabs (this);
134 VBox* b = manage (new VBox);
135 b->pack_start (*_group_tabs, PACK_SHRINK);
136 b->pack_start (strip_packer);
140 scroller.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC);
142 setup_track_display ();
144 group_model = ListStore::create (group_columns);
145 group_display.set_model (group_model);
146 group_display.append_column (_("Group"), group_columns.text);
147 group_display.append_column (_("Show"), group_columns.visible);
148 group_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
149 group_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
150 group_display.get_column (0)->set_expand(true);
151 group_display.get_column (1)->set_expand(false);
152 group_display.set_name ("EditGroupList");
153 group_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
154 group_display.set_reorderable (true);
155 group_display.set_headers_visible (true);
156 group_display.set_rules_hint (true);
157 group_display.set_can_focus(false);
159 /* name is directly editable */
161 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
162 name_cell->property_editable() = true;
163 name_cell->signal_edited().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_name_edit));
165 /* use checkbox for the active column */
167 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*>(group_display.get_column_cell_renderer (1));
168 active_cell->property_activatable() = true;
169 active_cell->property_radio() = false;
171 group_model->signal_row_changed().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_change));
172 /* We use this to notice drag-and-drop reorders of the group list */
173 group_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::route_group_row_deleted));
174 group_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::group_display_button_press), false);
176 group_display_scroller.add (group_display);
177 group_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
179 HBox* route_group_display_button_box = manage (new HBox());
181 Button* route_group_add_button = manage (new Button ());
182 Button* route_group_remove_button = manage (new Button ());
186 w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
188 route_group_add_button->add (*w);
190 w = manage (new Image (Stock::REMOVE, ICON_SIZE_BUTTON));
192 route_group_remove_button->add (*w);
194 route_group_display_button_box->set_homogeneous (true);
196 route_group_add_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_route_group));
197 route_group_remove_button->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::remove_selected_route_group));
199 route_group_display_button_box->add (*route_group_add_button);
200 route_group_display_button_box->add (*route_group_remove_button);
202 group_display_vbox.pack_start (group_display_scroller, true, true);
203 group_display_vbox.pack_start (*route_group_display_button_box, false, false);
205 group_display_frame.set_name ("BaseFrame");
206 group_display_frame.set_shadow_type (Gtk::SHADOW_IN);
207 group_display_frame.add (group_display_vbox);
210 list<TargetEntry> target_list;
211 target_list.push_back (TargetEntry ("PluginPresetPtr"));
213 favorite_plugins_model = PluginTreeStore::create (favorite_plugins_columns);
214 favorite_plugins_display.set_model (favorite_plugins_model);
215 favorite_plugins_display.append_column (_("Favorite Plugins"), favorite_plugins_columns.name);
216 favorite_plugins_display.set_name ("EditGroupList");
217 favorite_plugins_display.get_selection()->set_mode (Gtk::SELECTION_SINGLE);
218 favorite_plugins_display.set_reorderable (false);
219 favorite_plugins_display.set_headers_visible (true);
220 favorite_plugins_display.set_rules_hint (true);
221 favorite_plugins_display.set_can_focus (false);
222 favorite_plugins_display.add_object_drag (favorite_plugins_columns.plugin.index(), "PluginFavoritePtr");
223 favorite_plugins_display.set_drag_column (favorite_plugins_columns.name.index());
224 favorite_plugins_display.add_drop_targets (target_list);
225 favorite_plugins_display.signal_row_activated().connect (sigc::mem_fun (*this, &Mixer_UI::plugin_row_activated));
226 favorite_plugins_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::plugin_row_button_press), false);
227 favorite_plugins_display.signal_drop.connect (sigc::mem_fun (*this, &Mixer_UI::plugin_drop));
228 favorite_plugins_display.signal_row_expanded().connect (sigc::mem_fun (*this, &Mixer_UI::save_favorite_ui_state));
229 favorite_plugins_display.signal_row_collapsed().connect (sigc::mem_fun (*this, &Mixer_UI::save_favorite_ui_state));
230 favorite_plugins_model->signal_row_has_child_toggled().connect (sigc::mem_fun (*this, &Mixer_UI::sync_treeview_favorite_ui_state));
232 favorite_plugins_scroller.add (favorite_plugins_display);
233 favorite_plugins_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
235 favorite_plugins_frame.set_name ("BaseFrame");
236 favorite_plugins_frame.set_shadow_type (Gtk::SHADOW_IN);
237 favorite_plugins_frame.add (favorite_plugins_scroller);
239 rhs_pane1.pack1 (favorite_plugins_frame, false, true);
240 rhs_pane1.pack2 (track_display_frame);
241 rhs_pane2.pack1 (rhs_pane1);
242 rhs_pane2.pack2 (group_display_frame);
244 list_vpacker.pack_start (rhs_pane2, true, true);
246 vca_scroller.add (vca_packer);
247 vca_scroller.set_policy (Gtk::POLICY_ALWAYS, Gtk::POLICY_AUTOMATIC);
249 inner_pane.pack1 (scroller);
250 inner_pane.pack2 (vca_scroller);
252 global_hpacker.pack_start (inner_pane, true, true);
253 global_hpacker.pack_start (out_packer, false, false);
255 list_hpane.pack1(list_vpacker, false, true);
256 list_hpane.pack2(global_hpacker, true, false);
258 rhs_pane1.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
259 static_cast<Gtk::Paned*> (&rhs_pane1)));
260 rhs_pane2.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
261 static_cast<Gtk::Paned*> (&rhs_pane2)));
262 list_hpane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
263 static_cast<Gtk::Paned*> (&list_hpane)));
264 inner_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::pane_allocation_handler),
265 static_cast<Gtk::Paned*> (&inner_pane)));
267 _content.pack_start (list_hpane, true, true);
271 route_group_display_button_box->show();
272 route_group_add_button->show();
273 route_group_remove_button->show();
276 _content.set_name ("MixerWindow");
278 global_hpacker.show();
280 scroller_base.show();
281 scroller_hpacker.show();
282 mixer_scroller_vpacker.show();
284 group_display_button_label.show();
285 group_display_button.show();
286 group_display_scroller.show();
287 favorite_plugins_scroller.show();
288 group_display_vbox.show();
289 group_display_frame.show();
290 favorite_plugins_frame.show();
299 group_display.show();
300 favorite_plugins_display.show();
302 MixerStrip::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_strip, this, _1), gui_context());
304 #ifndef DEFER_PLUGIN_SELECTOR_LOAD
305 _plugin_selector = new PluginSelector (PluginManager::instance ());
307 #error implement deferred Plugin-Favorite list
309 PluginManager::instance ().PluginListChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context());
310 PluginManager::instance ().PluginStatusesChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context());
311 ARDOUR::Plugin::PresetsChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::refill_favorite_plugins, this), gui_context());
314 Mixer_UI::~Mixer_UI ()
316 if (_monitor_section) {
317 monitor_section_detached ();
318 delete _monitor_section;
320 delete _plugin_selector;
324 Mixer_UI::track_editor_selection ()
326 PublicEditor::instance().get_selection().TracksChanged.connect (sigc::mem_fun (*this, &Mixer_UI::follow_editor_selection));
330 Mixer_UI::use_own_window (bool and_fill_it)
332 bool new_window = !own_window();
334 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
337 if (win && new_window) {
338 win->set_name ("MixerWindow");
339 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Mixer"), this);
340 win->signal_scroll_event().connect (sigc::mem_fun (*this, &Mixer_UI::on_scroll_event), false);
341 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
342 win->set_data ("ardour-bindings", bindings);
350 Mixer_UI::show_window ()
352 Tabbable::show_window ();
354 /* show/hide group tabs as required */
355 parameter_changed ("show-group-tabs");
357 /* now reset each strips width so the right widgets are shown */
360 TreeModel::Children rows = track_model->children();
361 TreeModel::Children::iterator ri;
363 for (ri = rows.begin(); ri != rows.end(); ++ri) {
364 ms = (*ri)[track_columns.strip];
368 ms->set_width_enum (ms->get_width_enum (), ms->width_owner());
369 /* Fix visibility of mixer strip stuff */
370 ms->parameter_changed (X_("mixer-element-visibility"));
373 /* force focus into main area */
374 scroller_base.grab_focus ();
378 Mixer_UI::add_masters (VCAList& vcas)
380 for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
382 VCAMasterStrip* vms = new VCAMasterStrip (_session, *v);
384 TreeModel::Row row = *(track_model->append());
385 row[track_columns.text] = (*v)->name();
386 row[track_columns.visible] = true;
387 row[track_columns.vca] = vms;
389 vms->CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::remove_master, this, _1), gui_context());
392 redisplay_track_list ();
396 Mixer_UI::remove_master (VCAMasterStrip* vms)
398 if (_session && _session->deletion_in_progress()) {
399 /* its all being taken care of */
403 TreeModel::Children rows = track_model->children();
404 TreeModel::Children::iterator ri;
406 for (ri = rows.begin(); ri != rows.end(); ++ri) {
407 if ((*ri)[track_columns.vca] == vms) {
408 PBD::Unwinder<bool> uw (_route_deletion_in_progress, true);
409 track_model->erase (ri);
416 Mixer_UI::add_strips (RouteList& routes)
418 Gtk::TreeModel::Children::iterator insert_iter = track_model->children().end();
419 uint32_t nroutes = 0;
421 for (Gtk::TreeModel::Children::iterator it = track_model->children().begin(); it != track_model->children().end(); ++it) {
422 boost::shared_ptr<Route> r = (*it)[track_columns.route];
430 if (r->presentation_info().group_order() == (routes.front()->presentation_info().group_order() + routes.size())) {
437 _selection.clear_routes ();
443 no_track_list_redisplay = true;
444 track_display.set_model (Glib::RefPtr<ListStore>());
446 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
447 boost::shared_ptr<Route> route = (*x);
449 if (route->is_auditioner()) {
453 if (route->is_monitor()) {
455 if (!_monitor_section) {
456 _monitor_section = new MonitorSection (_session);
458 XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
460 _monitor_section->tearoff().set_state (*mnode);
464 out_packer.pack_end (_monitor_section->tearoff(), false, false);
465 _monitor_section->set_session (_session);
466 _monitor_section->tearoff().show_all ();
468 _monitor_section->tearoff().Detach.connect (sigc::mem_fun(*this, &Mixer_UI::monitor_section_detached));
469 _monitor_section->tearoff().Attach.connect (sigc::mem_fun(*this, &Mixer_UI::monitor_section_attached));
471 monitor_section_attached ();
473 route->DropReferences.connect (*this, invalidator(*this), boost::bind (&Mixer_UI::monitor_section_going_away, this), gui_context());
475 /* no regular strip shown for control out */
480 strip = new MixerStrip (*this, _session, route);
481 strips.push_back (strip);
483 UIConfiguration::instance().get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide;
485 if (strip->width_owner() != strip) {
486 strip->set_width_enum (_strip_width, this);
491 TreeModel::Row row = *(track_model->insert(insert_iter));
492 row[track_columns.text] = route->name();
493 row[track_columns.visible] = strip->route()->is_master() ? true : strip->marked_for_display();
494 row[track_columns.route] = route;
495 row[track_columns.strip] = strip;
496 row[track_columns.vca] = 0;
499 _selection.add (strip);
502 route->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::strip_property_changed, this, _1, strip), gui_context());
504 strip->WidthChanged.connect (sigc::mem_fun(*this, &Mixer_UI::strip_width_changed));
505 strip->signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::strip_button_release_event), strip));
508 } catch (const std::exception& e) {
509 error << string_compose (_("Error adding GUI elements for new tracks/busses %1"), e.what()) << endmsg;
512 no_track_list_redisplay = false;
513 track_display.set_model (track_model);
515 sync_presentation_info_from_treeview ();
516 redisplay_track_list ();
520 Mixer_UI::deselect_all_strip_processors ()
522 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
523 (*i)->deselect_all_processors();
528 Mixer_UI::select_strip (MixerStrip& ms, bool add)
531 _selection.add (&ms);
533 _selection.set (&ms);
538 Mixer_UI::select_none ()
540 _selection.clear_routes();
541 deselect_all_strip_processors();
545 Mixer_UI::delete_processors ()
547 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
548 (*i)->delete_processors();
554 Mixer_UI::remove_strip (MixerStrip* strip)
556 if (_session && _session->deletion_in_progress()) {
557 /* its all being taken care of */
561 TreeModel::Children rows = track_model->children();
562 TreeModel::Children::iterator ri;
563 list<MixerStrip *>::iterator i;
565 if ((i = find (strips.begin(), strips.end(), strip)) != strips.end()) {
569 for (ri = rows.begin(); ri != rows.end(); ++ri) {
570 if ((*ri)[track_columns.strip] == strip) {
571 PBD::Unwinder<bool> uw (_route_deletion_in_progress, true);
572 track_model->erase (ri);
579 Mixer_UI::sync_presentation_info_from_treeview ()
581 if (ignore_reorder || !_session || _session->deletion_in_progress() || (Config->get_remote_model() != MixerOrdered)) {
585 TreeModel::Children rows = track_model->children();
591 DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync presentation info from treeview\n");
593 TreeModel::Children::iterator ri;
597 for (ri = rows.begin(); ri != rows.end(); ++ri) {
598 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
599 bool visible = (*ri)[track_columns.visible];
606 if (route->presentation_info().special()) {
611 route->presentation_info().set_flag (PresentationInfo::Hidden);
613 route->presentation_info().unset_flag (PresentationInfo::Hidden);
616 if (order != route->presentation_info().group_order()) {
617 route->set_presentation_group_order_explicit (order);
625 DEBUG_TRACE (DEBUG::OrderKeys, "... notify PI change from mixer GUI\n");
626 _session->notify_presentation_info_change ();
631 Mixer_UI::sync_treeview_from_presentation_info ()
633 if (!_session || _session->deletion_in_progress()) {
637 DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync model from presentation info.\n");
639 /* we could get here after either a change in the Mixer or Editor sort
640 * order, but either way, the mixer order keys reflect the intended
641 * order for the GUI, so reorder the treeview model to match it.
644 vector<int> neworder;
645 TreeModel::Children rows = track_model->children();
646 uint32_t old_order = 0;
647 bool changed = false;
654 uint32_t vca_cnt = 0;
655 uint32_t max_route_order_key = 0;
657 /* count number of Routes in track_model (there may be some odd reason
658 why this is not the same as the number in the session, but here we
659 care about the track model.
662 for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri) {
663 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
665 max_route_order_key = max (route->presentation_info().group_order(), max_route_order_key);
669 for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
670 boost::shared_ptr<Route> route = (*ri)[track_columns.route];
672 /* VCAs need to sort after all routes. We don't display
673 * them in the same place (March 2016), but we don't
674 * want them intermixed in the track_model
676 sorted.push_back (OrderKeys (old_order, max_route_order_key + ++vca_cnt));
678 sorted.push_back (OrderKeys (old_order, route->presentation_info().group_order()));
682 SortByNewDisplayOrder cmp;
684 sort (sorted.begin(), sorted.end(), cmp);
685 neworder.assign (sorted.size(), 0);
689 for (OrderingKeys::iterator sr = sorted.begin(); sr != sorted.end(); ++sr, ++n) {
691 neworder[n] = sr->old_display_order;
693 if (sr->old_display_order != n) {
699 Unwinder<bool> uw (ignore_reorder, true);
700 track_model->reorder (neworder);
703 redisplay_track_list ();
707 Mixer_UI::follow_editor_selection ()
709 if (_following_editor_selection) {
713 _following_editor_selection = true;
714 _selection.block_routes_changed (true);
716 TrackSelection& s (PublicEditor::instance().get_selection().tracks);
718 _selection.clear_routes ();
720 for (TrackViewList::iterator i = s.begin(); i != s.end(); ++i) {
721 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*i);
723 MixerStrip* ms = strip_by_route (rtav->route());
730 _following_editor_selection = false;
731 _selection.block_routes_changed (false);
736 Mixer_UI::strip_by_route (boost::shared_ptr<Route> r)
738 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
739 if ((*i)->route() == r) {
748 Mixer_UI::strip_button_release_event (GdkEventButton *ev, MixerStrip *strip)
750 if (ev->button == 1) {
751 if (_selection.selected (strip)) {
752 /* primary-click: toggle selection state of strip */
753 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
754 _selection.remove (strip);
755 } else if (_selection.routes.size() > 1) {
756 /* de-select others */
757 _selection.set (strip);
760 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
761 _selection.add (strip);
762 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::RangeSelectModifier)) {
764 if (!_selection.selected(strip)) {
766 /* extend selection */
768 vector<MixerStrip*> tmp;
769 bool accumulate = false;
770 bool found_another = false;
772 tmp.push_back (strip);
774 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
776 /* hit clicked strip, start accumulating till we hit the first
785 } else if (_selection.selected (*i)) {
786 /* hit selected strip. if currently accumulating others,
787 we're done. if not accumulating others, start doing so.
789 found_another = true;
804 for (vector<MixerStrip*>::iterator i = tmp.begin(); i != tmp.end(); ++i) {
808 _selection.set (strip); //user wants to start a range selection, but there aren't any others selected yet
812 _selection.set (strip);
821 Mixer_UI::set_session (Session* sess)
823 SessionHandlePtr::set_session (sess);
825 if (_plugin_selector) {
826 _plugin_selector->set_session (_session);
829 _group_tabs->set_session (sess);
835 refill_favorite_plugins();
837 XMLNode* node = ARDOUR_UI::instance()->mixer_settings();
838 set_state (*node, 0);
842 initial_track_display ();
844 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_strips, this, _1), gui_context());
845 _session->route_group_added.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_route_group, this, _1), gui_context());
846 _session->route_group_removed.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
847 _session->route_groups_reordered.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
848 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::parameter_changed, this, _1), gui_context());
849 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::update_title, this), gui_context());
850 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::update_title, this), gui_context());
852 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_masters, this, _1), gui_context());
854 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::parameter_changed, this, _1), gui_context ());
856 route_groups_changed ();
865 Mixer_UI::session_going_away ()
867 ENSURE_GUI_THREAD (*this, &Mixer_UI::session_going_away);
869 _in_group_rebuild_or_clear = true;
870 group_model->clear ();
871 _in_group_rebuild_or_clear = false;
874 track_model->clear ();
876 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
880 if (_monitor_section) {
881 _monitor_section->tearoff().hide_visible ();
884 monitor_section_detached ();
890 SessionHandlePtr::session_going_away ();
897 Mixer_UI::track_visibility_changed (std::string const & path)
899 if (_session && _session->deletion_in_progress()) {
905 if ((iter = track_model->get_iter (path))) {
906 MixerStrip* strip = (*iter)[track_columns.strip];
908 bool visible = (*iter)[track_columns.visible];
910 if (strip->set_marked_for_display (!visible)) {
911 update_track_visibility ();
918 Mixer_UI::update_track_visibility ()
920 TreeModel::Children rows = track_model->children();
921 TreeModel::Children::iterator i;
924 Unwinder<bool> uw (no_track_list_redisplay, true);
926 for (i = rows.begin(); i != rows.end(); ++i) {
927 MixerStrip *strip = (*i)[track_columns.strip];
929 (*i)[track_columns.visible] = strip->marked_for_display ();
933 /* force presentation catch up with visibility changes
936 sync_presentation_info_from_treeview ();
939 redisplay_track_list ();
943 Mixer_UI::show_strip (MixerStrip* ms)
945 TreeModel::Children rows = track_model->children();
946 TreeModel::Children::iterator i;
948 for (i = rows.begin(); i != rows.end(); ++i) {
950 MixerStrip* strip = (*i)[track_columns.strip];
952 (*i)[track_columns.visible] = true;
953 redisplay_track_list ();
960 Mixer_UI::hide_strip (MixerStrip* ms)
962 TreeModel::Children rows = track_model->children();
963 TreeModel::Children::iterator i;
965 for (i = rows.begin(); i != rows.end(); ++i) {
967 MixerStrip* strip = (*i)[track_columns.strip];
969 (*i)[track_columns.visible] = false;
970 redisplay_track_list ();
977 Mixer_UI::start_updating ()
979 fast_screen_update_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &Mixer_UI::fast_update_strips));
984 Mixer_UI::stop_updating ()
986 fast_screen_update_connection.disconnect();
991 Mixer_UI::fast_update_strips ()
993 if (_content.is_mapped () && _session) {
994 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
995 (*i)->fast_update ();
1001 Mixer_UI::set_all_strips_visibility (bool yn)
1003 TreeModel::Children rows = track_model->children();
1004 TreeModel::Children::iterator i;
1007 Unwinder<bool> uw (no_track_list_redisplay, true);
1009 for (i = rows.begin(); i != rows.end(); ++i) {
1011 TreeModel::Row row = (*i);
1012 MixerStrip* strip = row[track_columns.strip];
1018 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1022 (*i)[track_columns.visible] = yn;
1026 redisplay_track_list ();
1031 Mixer_UI::set_all_audio_midi_visibility (int tracks, bool yn)
1033 TreeModel::Children rows = track_model->children();
1034 TreeModel::Children::iterator i;
1037 Unwinder<bool> uw (no_track_list_redisplay, true);
1039 for (i = rows.begin(); i != rows.end(); ++i) {
1040 TreeModel::Row row = (*i);
1041 MixerStrip* strip = row[track_columns.strip];
1047 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1051 boost::shared_ptr<AudioTrack> at = strip->audio_track();
1052 boost::shared_ptr<MidiTrack> mt = strip->midi_track();
1056 (*i)[track_columns.visible] = yn;
1060 if (at) { /* track */
1061 (*i)[track_columns.visible] = yn;
1066 if (!at && !mt) { /* bus */
1067 (*i)[track_columns.visible] = yn;
1072 if (mt) { /* midi-track */
1073 (*i)[track_columns.visible] = yn;
1080 redisplay_track_list ();
1084 Mixer_UI::hide_all_routes ()
1086 set_all_strips_visibility (false);
1090 Mixer_UI::show_all_routes ()
1092 set_all_strips_visibility (true);
1096 Mixer_UI::show_all_audiobus ()
1098 set_all_audio_midi_visibility (2, true);
1101 Mixer_UI::hide_all_audiobus ()
1103 set_all_audio_midi_visibility (2, false);
1107 Mixer_UI::show_all_audiotracks()
1109 set_all_audio_midi_visibility (1, true);
1112 Mixer_UI::hide_all_audiotracks ()
1114 set_all_audio_midi_visibility (1, false);
1118 Mixer_UI::show_all_miditracks()
1120 set_all_audio_midi_visibility (3, true);
1123 Mixer_UI::hide_all_miditracks ()
1125 set_all_audio_midi_visibility (3, false);
1130 Mixer_UI::track_list_reorder (const TreeModel::Path&, const TreeModel::iterator&, int* /*new_order*/)
1132 DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview reordered\n");
1133 sync_presentation_info_from_treeview ();
1137 Mixer_UI::track_list_delete (const Gtk::TreeModel::Path&)
1139 /* this happens as the second step of a DnD within the treeview as well
1140 as when a row/route is actually deleted.
1142 if it was a deletion then we have to force a redisplay because
1143 order keys may not have changed.
1146 DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview row deleted\n");
1147 sync_presentation_info_from_treeview ();
1149 if (_route_deletion_in_progress) {
1150 redisplay_track_list ();
1155 Mixer_UI::redisplay_track_list ()
1157 TreeModel::Children rows = track_model->children();
1158 TreeModel::Children::iterator i;
1159 uint32_t n_masters = 0;
1161 if (no_track_list_redisplay) {
1165 container_clear (vca_packer);
1167 for (i = rows.begin(); i != rows.end(); ++i) {
1169 VCAMasterStrip* vms = (*i)[track_columns.vca];
1172 vca_packer.pack_start (*vms, false, false);
1178 MixerStrip* strip = (*i)[track_columns.strip];
1181 /* we're in the middle of changing a row, don't worry */
1185 bool const visible = (*i)[track_columns.visible];
1188 strip->set_gui_property ("visible", true);
1190 if (strip->packed()) {
1192 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1193 out_packer.reorder_child (*strip, -1);
1196 strip_packer.reorder_child (*strip, -1); /* put at end */
1201 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1202 out_packer.pack_start (*strip, false, false);
1204 strip_packer.pack_start (*strip, false, false);
1206 strip->set_packed (true);
1211 strip->set_gui_property ("visible", false);
1213 if (strip->route()->is_master() || strip->route()->is_monitor()) {
1214 /* do nothing, these cannot be hidden */
1216 if (strip->packed()) {
1217 strip_packer.remove (*strip);
1218 strip->set_packed (false);
1224 /* update visibility of VCA assign buttons */
1226 if (n_masters == 0) {
1227 UIConfiguration::instance().set_mixer_strip_visibility (VisibilityGroup::remove_element (UIConfiguration::instance().get_mixer_strip_visibility(), X_("VCA")));
1228 vca_scroller.hide ();
1230 UIConfiguration::instance().set_mixer_strip_visibility (VisibilityGroup::add_element (UIConfiguration::instance().get_mixer_strip_visibility(), X_("VCA")));
1231 vca_scroller.show ();
1234 _group_tabs->set_dirty ();
1238 Mixer_UI::strip_width_changed ()
1240 _group_tabs->set_dirty ();
1243 TreeModel::Children rows = track_model->children();
1244 TreeModel::Children::iterator i;
1247 for (order = 0, i = rows.begin(); i != rows.end(); ++i, ++order) {
1248 MixerStrip* strip = (*i)[track_columns.strip];
1254 bool visible = (*i)[track_columns.visible];
1257 strip->queue_draw();
1264 struct PresentationInfoRouteSorter
1266 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1267 return a->presentation_info().global_order () < b->presentation_info().global_order ();
1272 Mixer_UI::initial_track_display ()
1274 boost::shared_ptr<RouteList> routes = _session->get_routes();
1275 RouteList copy (*routes);
1276 PresentationInfoRouteSorter sorter;
1281 Unwinder<bool> uw1 (no_track_list_redisplay, true);
1282 Unwinder<bool> uw2 (ignore_reorder, true);
1284 track_model->clear ();
1285 VCAList vcas = _session->vca_manager().vcas();
1290 redisplay_track_list ();
1294 Mixer_UI::show_track_list_menu ()
1296 if (track_menu == 0) {
1297 build_track_menu ();
1300 track_menu->popup (1, gtk_get_current_event_time());
1304 Mixer_UI::track_display_button_press (GdkEventButton* ev)
1306 if (Keyboard::is_context_menu_event (ev)) {
1307 show_track_list_menu ();
1315 Mixer_UI::build_track_menu ()
1317 using namespace Menu_Helpers;
1318 using namespace Gtk;
1320 track_menu = new Menu;
1321 track_menu->set_name ("ArdourContextMenu");
1322 MenuList& items = track_menu->items();
1324 items.push_back (MenuElem (_("Show All"), sigc::mem_fun(*this, &Mixer_UI::show_all_routes)));
1325 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun(*this, &Mixer_UI::hide_all_routes)));
1326 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiotracks)));
1327 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiotracks)));
1328 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::show_all_audiobus)));
1329 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun(*this, &Mixer_UI::hide_all_audiobus)));
1330 items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &Mixer_UI::show_all_miditracks)));
1331 items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &Mixer_UI::hide_all_miditracks)));
1336 Mixer_UI::strip_property_changed (const PropertyChange& what_changed, MixerStrip* mx)
1338 if (!what_changed.contains (ARDOUR::Properties::name)) {
1342 ENSURE_GUI_THREAD (*this, &Mixer_UI::strip_name_changed, what_changed, mx)
1344 TreeModel::Children rows = track_model->children();
1345 TreeModel::Children::iterator i;
1347 for (i = rows.begin(); i != rows.end(); ++i) {
1348 if ((*i)[track_columns.strip] == mx) {
1349 (*i)[track_columns.text] = mx->route()->name();
1354 error << _("track display list item for renamed strip not found!") << endmsg;
1358 Mixer_UI::group_display_button_press (GdkEventButton* ev)
1360 TreeModel::Path path;
1361 TreeViewColumn* column;
1365 if (!group_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
1366 _group_tabs->get_menu(0)->popup (1, ev->time);
1370 TreeIter iter = group_model->get_iter (path);
1372 _group_tabs->get_menu(0)->popup (1, ev->time);
1376 RouteGroup* group = (*iter)[group_columns.group];
1378 if (Keyboard::is_context_menu_event (ev)) {
1379 _group_tabs->get_menu(group)->popup (1, ev->time);
1383 switch (GPOINTER_TO_UINT (column->get_data (X_("colnum")))) {
1385 if (Keyboard::is_edit_event (ev)) {
1387 // edit_route_group (group);
1389 group_display.queue_draw();
1398 bool visible = (*iter)[group_columns.visible];
1399 (*iter)[group_columns.visible] = !visible;
1401 group_display.queue_draw();
1414 Mixer_UI::activate_all_route_groups ()
1416 _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), true));
1420 Mixer_UI::disable_all_route_groups ()
1422 _session->foreach_route_group (sigc::bind (sigc::mem_fun (*this, &Mixer_UI::set_route_group_activation), false));
1426 Mixer_UI::route_groups_changed ()
1428 ENSURE_GUI_THREAD (*this, &Mixer_UI::route_groups_changed);
1430 _in_group_rebuild_or_clear = true;
1432 /* just rebuild the while thing */
1434 group_model->clear ();
1437 /* this is currently not used,
1438 * Mixer_UI::group_display_button_press() has a case for it,
1439 * and a commented edit_route_group() but that's n/a since 2011.
1441 * This code is left as reminder that
1442 * row[group_columns.group] = 0 has special meaning.
1446 row = *(group_model->append());
1447 row[group_columns.visible] = true;
1448 row[group_columns.text] = (_("-all-"));
1449 row[group_columns.group] = 0;
1453 _session->foreach_route_group (sigc::mem_fun (*this, &Mixer_UI::add_route_group));
1455 _group_tabs->set_dirty ();
1456 _in_group_rebuild_or_clear = false;
1460 Mixer_UI::new_route_group ()
1464 _group_tabs->run_new_group_dialog (rl);
1468 Mixer_UI::remove_selected_route_group ()
1470 Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1471 TreeView::Selection::ListHandle_Path rows = selection->get_selected_rows ();
1477 TreeView::Selection::ListHandle_Path::iterator i = rows.begin();
1480 /* selection mode is single, so rows.begin() is it */
1482 if ((iter = group_model->get_iter (*i))) {
1484 RouteGroup* rg = (*iter)[group_columns.group];
1487 _session->remove_route_group (*rg);
1493 Mixer_UI::route_group_property_changed (RouteGroup* group, const PropertyChange& change)
1495 if (in_group_row_change) {
1499 /* force an update of any mixer strips that are using this group,
1500 otherwise mix group names don't change in mixer strips
1503 for (list<MixerStrip *>::iterator i = strips.begin(); i != strips.end(); ++i) {
1504 if ((*i)->route_group() == group) {
1505 (*i)->route_group_changed();
1509 TreeModel::iterator i;
1510 TreeModel::Children rows = group_model->children();
1511 Glib::RefPtr<TreeSelection> selection = group_display.get_selection();
1513 in_group_row_change = true;
1515 for (i = rows.begin(); i != rows.end(); ++i) {
1516 if ((*i)[group_columns.group] == group) {
1517 (*i)[group_columns.visible] = !group->is_hidden ();
1518 (*i)[group_columns.text] = group->name ();
1523 in_group_row_change = false;
1525 if (change.contains (Properties::name)) {
1526 _group_tabs->set_dirty ();
1529 for (list<MixerStrip*>::iterator j = strips.begin(); j != strips.end(); ++j) {
1530 if ((*j)->route_group() == group) {
1531 if (group->is_hidden ()) {
1541 Mixer_UI::show_mixer_list (bool yn)
1544 list_vpacker.show ();
1546 //if user wants to show the pane, we should make sure that it is wide enough to be visible
1547 int width = list_hpane.get_position();
1549 list_hpane.set_position(40);
1552 list_vpacker.hide ();
1555 _show_mixer_list = yn;
1559 Mixer_UI::show_monitor_section (bool yn)
1561 if (!monitor_section()) {
1564 if (monitor_section()->tearoff().torn_off()) {
1569 monitor_section()->tearoff().show();
1571 monitor_section()->tearoff().hide();
1576 Mixer_UI::route_group_name_edit (const std::string& path, const std::string& new_text)
1581 if ((iter = group_model->get_iter (path))) {
1583 if ((group = (*iter)[group_columns.group]) == 0) {
1587 if (new_text != group->name()) {
1588 group->set_name (new_text);
1594 Mixer_UI::route_group_row_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator& iter)
1598 if (in_group_row_change) {
1602 if ((group = (*iter)[group_columns.group]) == 0) {
1606 std::string name = (*iter)[group_columns.text];
1608 if (name != group->name()) {
1609 group->set_name (name);
1612 bool hidden = !(*iter)[group_columns.visible];
1614 if (hidden != group->is_hidden ()) {
1615 group->set_hidden (hidden, this);
1619 /** Called when a group model row is deleted, but also when the model is
1620 * reordered by a user drag-and-drop; the latter is what we are
1621 * interested in here.
1624 Mixer_UI::route_group_row_deleted (Gtk::TreeModel::Path const &)
1626 if (_in_group_rebuild_or_clear) {
1630 /* Re-write the session's route group list so that the new order is preserved */
1632 list<RouteGroup*> new_list;
1634 Gtk::TreeModel::Children children = group_model->children();
1635 for (Gtk::TreeModel::Children::iterator i = children.begin(); i != children.end(); ++i) {
1636 RouteGroup* g = (*i)[group_columns.group];
1638 new_list.push_back (g);
1642 _session->reorder_route_groups (new_list);
1647 Mixer_UI::add_route_group (RouteGroup* group)
1649 ENSURE_GUI_THREAD (*this, &Mixer_UI::add_route_group, group)
1652 in_group_row_change = true;
1654 TreeModel::Row row = *(group_model->append());
1655 row[group_columns.visible] = !group->is_hidden ();
1656 row[group_columns.group] = group;
1657 if (!group->name().empty()) {
1658 row[group_columns.text] = group->name();
1660 row[group_columns.text] = _("unnamed");
1664 group->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::route_group_property_changed, this, group, _1), gui_context());
1667 TreeViewColumn* col = group_display.get_column (0);
1668 CellRendererText* name_cell = dynamic_cast<CellRendererText*>(group_display.get_column_cell_renderer (0));
1669 group_display.set_cursor (group_model->get_path (row), *col, *name_cell, true);
1672 _group_tabs->set_dirty ();
1674 in_group_row_change = false;
1678 Mixer_UI::strip_scroller_button_release (GdkEventButton* ev)
1680 using namespace Menu_Helpers;
1682 if (Keyboard::is_context_menu_event (ev)) {
1683 ARDOUR_UI::instance()->add_route ();
1691 Mixer_UI::scroller_drag_data_received (const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, const Gtk::SelectionData& data, guint info, guint time)
1693 printf ("Mixer_UI::scroller_drag_data_received\n");
1694 if (data.get_target() != "PluginFavoritePtr") {
1695 context->drag_finish (false, false, time);
1699 const void * d = data.get_data();
1700 const Gtkmm2ext::DnDTreeView<ARDOUR::PluginPresetPtr>* tv = reinterpret_cast<const Gtkmm2ext::DnDTreeView<ARDOUR::PluginPresetPtr>*>(d);
1702 PluginPresetList nfos;
1704 tv->get_object_drag_data (nfos, &source);
1706 Route::ProcessorList pl;
1709 for (list<PluginPresetPtr>::const_iterator i = nfos.begin(); i != nfos.end(); ++i) {
1710 PluginPresetPtr ppp = (*i);
1711 PluginInfoPtr pip = ppp->_pip;
1712 if (!pip->is_instrument ()) {
1715 ARDOUR_UI::instance()->session_add_midi_track ((RouteGroup*) 0, 1, _("MIDI"), Config->get_strict_io (), pip, ppp->_preset.valid ? &ppp->_preset : 0, PresentationInfo::max_order);
1719 context->drag_finish (ok, false, time);
1723 Mixer_UI::set_strip_width (Width w, bool save)
1727 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
1728 (*i)->set_width_enum (w, save ? (*i)->width_owner() : this);
1733 struct PluginStateSorter {
1735 bool operator() (PluginInfoPtr a, PluginInfoPtr b) const {
1736 std::list<std::string>::const_iterator aiter = std::find(_user.begin(), _user.end(), (*a).unique_id);
1737 std::list<std::string>::const_iterator biter = std::find(_user.begin(), _user.end(), (*b).unique_id);
1738 if (aiter != _user.end() && biter != _user.end()) {
1739 return std::distance (_user.begin(), aiter) < std::distance (_user.begin(), biter);
1741 if (aiter != _user.end()) {
1744 if (biter != _user.end()) {
1747 return ARDOUR::cmp_nocase((*a).name, (*b).name) == -1;
1750 PluginStateSorter(std::list<std::string> user) : _user (user) {}
1752 std::list<std::string> _user;
1756 Mixer_UI::set_state (const XMLNode& node, int version)
1758 XMLProperty const * prop;
1760 Tabbable::set_state (node, version);
1762 if ((prop = node.property ("narrow-strips"))) {
1763 if (string_is_affirmative (prop->value())) {
1764 set_strip_width (Narrow);
1766 set_strip_width (Wide);
1770 if ((prop = node.property ("show-mixer"))) {
1771 if (string_is_affirmative (prop->value())) {
1776 if ((prop = node.property ("maximised"))) {
1777 bool yn = string_is_affirmative (prop->value());
1778 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalMixer"));
1780 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1781 bool fs = tact && tact->get_active();
1783 ActionManager::do_action ("Common", "ToggleMaximalMixer");
1787 if ((prop = node.property ("show-mixer-list"))) {
1788 bool yn = string_is_affirmative (prop->value());
1789 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMixerList"));
1791 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
1793 /* do it twice to force the change */
1794 tact->set_active (!yn);
1795 tact->set_active (yn);
1799 XMLNode* plugin_order;
1800 if ((plugin_order = find_named_node (node, "PluginOrder")) != 0) {
1801 store_current_favorite_order ();
1802 std::list<string> order;
1803 const XMLNodeList& kids = plugin_order->children("PluginInfo");
1804 XMLNodeConstIterator i;
1805 for (i = kids.begin(); i != kids.end(); ++i) {
1806 if ((prop = (*i)->property ("unique-id"))) {
1807 std::string unique_id = prop->value();
1808 order.push_back (unique_id);
1809 if ((prop = (*i)->property ("expanded"))) {
1810 favorite_ui_state[unique_id] = string_is_affirmative (prop->value());
1814 PluginStateSorter cmp (order);
1815 favorite_order.sort (cmp);
1816 sync_treeview_from_favorite_order ();
1822 Mixer_UI::get_state ()
1824 XMLNode* node = new XMLNode (X_("Mixer"));
1827 node->add_child_nocopy (Tabbable::get_state());
1829 snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (rhs_pane1, true));
1830 node->add_property(X_("mixer-rhs-pane1-pos"), string(buf));
1831 snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (rhs_pane2, true));
1832 node->add_property(X_("mixer-rhs_pane2-pos"), string(buf));
1833 snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (list_hpane, false));
1834 node->add_property(X_("mixer-list-hpane-pos"), string(buf));
1835 snprintf(buf,sizeof(buf), "%f", paned_position_as_fraction (inner_pane, false));
1836 node->add_property(X_("mixer-inner-pane-pos"), string(buf));
1838 node->add_property ("narrow-strips", _strip_width == Narrow ? "yes" : "no");
1839 node->add_property ("show-mixer", _visible ? "yes" : "no");
1840 node->add_property ("show-mixer-list", _show_mixer_list ? "yes" : "no");
1841 node->add_property ("maximised", _maximised ? "yes" : "no");
1843 store_current_favorite_order ();
1844 XMLNode* plugin_order = new XMLNode ("PluginOrder");
1846 for (PluginInfoList::const_iterator i = favorite_order.begin(); i != favorite_order.end(); ++i, ++cnt) {
1847 XMLNode* p = new XMLNode ("PluginInfo");
1848 p->add_property ("sort", cnt);
1849 p->add_property ("unique-id", (*i)->unique_id);
1850 if (favorite_ui_state.find ((*i)->unique_id) != favorite_ui_state.end ()) {
1851 p->add_property ("expanded", favorite_ui_state[(*i)->unique_id]);
1853 plugin_order->add_child_nocopy (*p);
1855 node->add_child_nocopy (*plugin_order);
1861 Mixer_UI::pane_allocation_handler (Allocation& allocation, Gtk::Paned* which)
1864 XMLProperty* prop = 0;
1865 XMLNode* geometry = ARDOUR_UI::instance()->mixer_settings();
1866 int height = default_height;
1867 static bool done[4] = { false, false, false, false };
1869 /* Gtk::Paned behaves very oddly and rather undesirably. Setting the
1870 * position is a crapshoot if you time it incorrectly with the overall
1871 * sizing of the Paned. For example, if you might retrieve the size with
1872 * ::get_position() and then later call ::set_position() on a Paned at
1873 * a time when its allocation is different than it was when you retrieved
1874 * the position. The position will be interpreted as the size of the
1875 * first (top or left) child widget. If packing/size allocation later
1876 * resizes the Paned to a (final) smaller size, the position will be
1877 * used in ways that mean that the Paned ends up NOT in the same state
1878 * that it was in when you originally saved the position.
1880 * Concrete example: Paned is 800 pixels wide, position is 400
1881 * (halfway). Save position as 400. During program restart, set
1882 * position to 400, before Paned has been allocated any space. Paned
1883 * ends up initially sized to 1200 pixels. Position is now 1/3 of the
1884 * way across/down. Subsequent resizes will leave the position 1/3 of
1885 * the way across, rather than leaving it as a fixed pixel
1886 * position. Eventually, the Paned ends up 800 pixels wide/high again,
1887 * but the position is now 267, not 400.
1891 * We deal with this by using two strategies:
1893 * 1) only set the position if the allocated size of the Paned is at
1894 * least as big as it needs to be for the position to make sense.
1896 * 2) in recent versions of Ardour, save the position as a fraction,
1897 * and restore it using that fraction.
1899 * So, we will only call ::set_position() AFTER the Paned is of a
1900 * sensible size, and then in addition, we will set the position in a
1901 * way that will be maintained as/when/if the Paned is resized.
1903 * Once we've called ::set_position() on a Paned, we don't do it
1907 if (which == static_cast<Gtk::Paned*> (&rhs_pane1)) {
1913 if (!geometry || (prop = geometry->property("mixer-rhs-pane1-pos")) == 0) {
1916 pos = atof (prop->value());
1920 /* older versions of Ardour stored absolute position */
1921 if ((done[0] = (allocation.get_height() > pos))) {
1922 rhs_pane1.set_position (pos);
1925 if ((done[0] = (allocation.get_height() > 1.0/pos))) {
1926 paned_set_position_as_fraction (rhs_pane1, pos, true);
1931 if (which == static_cast<Gtk::Paned*> (&rhs_pane2)) {
1937 if (!geometry || (prop = geometry->property("mixer-rhs-pane2-pos")) == 0) {
1938 pos = 2 * height / 3;
1940 pos = atof (prop->value());
1944 /* older versions of Ardour stored absolute position */
1945 if ((done[1] = (allocation.get_height() > pos))) {
1946 rhs_pane2.set_position (pos);
1949 if ((done[1] = (allocation.get_height() > 1.0/pos))) {
1950 paned_set_position_as_fraction (rhs_pane2, pos, true);
1955 if (which == static_cast<Gtk::Paned*> (&list_hpane)) {
1961 if (!geometry || (prop = geometry->property("mixer-list-hpane-pos")) == 0) {
1962 pos = std::max ((float)100, rintf ((float) 125 * UIConfiguration::instance().get_ui_scale()));
1964 pos = max (0.1, atof (prop->value ()));
1968 if ((done[2] = (allocation.get_width() > pos))) {
1969 list_hpane.set_position (pos);
1972 if ((done[2] = (allocation.get_width() > 1.0/pos))) {
1973 paned_set_position_as_fraction (list_hpane, pos, false);
1978 if (which == static_cast<Gtk::Paned*> (&inner_pane)) {
1984 if (!geometry || (prop = geometry->property("mixer-inner-pane-pos")) == 0) {
1985 pos = std::max ((float)100, rintf ((float) 125 * UIConfiguration::instance().get_ui_scale()));
1987 pos = max (0.1, atof (prop->value ()));
1991 /* older versions of Ardour stored absolute position */
1992 if ((done[3] = (allocation.get_width() > pos))) {
1993 inner_pane.set_position (pos);
1996 if ((done[3] = (allocation.get_width() > 1.0/pos))) {
1997 paned_set_position_as_fraction (inner_pane, pos, false);
2004 Mixer_UI::scroll_left ()
2006 if (!scroller.get_hscrollbar()) return;
2007 Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
2008 /* stupid GTK: can't rely on clamping across versions */
2009 scroller.get_hscrollbar()->set_value (max (adj->get_lower(), adj->get_value() - adj->get_step_increment()));
2013 Mixer_UI::scroll_right ()
2015 if (!scroller.get_hscrollbar()) return;
2016 Adjustment* adj = scroller.get_hscrollbar()->get_adjustment();
2017 /* stupid GTK: can't rely on clamping across versions */
2018 scroller.get_hscrollbar()->set_value (min (adj->get_upper(), adj->get_value() + adj->get_step_increment()));
2022 Mixer_UI::on_scroll_event (GdkEventScroll* ev)
2024 switch (ev->direction) {
2025 case GDK_SCROLL_LEFT:
2029 if (ev->state & Keyboard::TertiaryModifier) {
2035 case GDK_SCROLL_RIGHT:
2039 case GDK_SCROLL_DOWN:
2040 if (ev->state & Keyboard::TertiaryModifier) {
2052 Mixer_UI::parameter_changed (string const & p)
2054 if (p == "show-group-tabs") {
2055 bool const s = _session->config.get_show_group_tabs ();
2057 _group_tabs->show ();
2059 _group_tabs->hide ();
2061 } else if (p == "default-narrow_ms") {
2062 bool const s = UIConfiguration::instance().get_default_narrow_ms ();
2063 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
2064 (*i)->set_width_enum (s ? Narrow : Wide, this);
2066 } else if (p == "use-monitor-bus") {
2067 if (_session && !_session->monitor_out()) {
2068 monitor_section_detached ();
2074 Mixer_UI::set_route_group_activation (RouteGroup* g, bool a)
2076 g->set_active (a, this);
2080 Mixer_UI::plugin_selector()
2082 #ifdef DEFER_PLUGIN_SELECTOR_LOAD
2083 if (!_plugin_selector)
2084 _plugin_selector = new PluginSelector (PluginManager::instance());
2087 return _plugin_selector;
2091 Mixer_UI::setup_track_display ()
2093 track_model = ListStore::create (track_columns);
2094 track_display.set_model (track_model);
2095 track_display.append_column (_("Strips"), track_columns.text);
2096 track_display.append_column (_("Show"), track_columns.visible);
2097 track_display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
2098 track_display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
2099 track_display.get_column (0)->set_expand(true);
2100 track_display.get_column (1)->set_expand(false);
2101 track_display.get_column (0)->set_sizing (Gtk::TREE_VIEW_COLUMN_FIXED);
2102 track_display.set_name (X_("EditGroupList"));
2103 track_display.get_selection()->set_mode (Gtk::SELECTION_NONE);
2104 track_display.set_reorderable (true);
2105 track_display.set_headers_visible (true);
2106 track_display.set_can_focus(false);
2108 track_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_delete));
2109 track_model->signal_rows_reordered().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_reorder));
2111 CellRendererToggle* track_list_visible_cell = dynamic_cast<CellRendererToggle*>(track_display.get_column_cell_renderer (1));
2112 track_list_visible_cell->property_activatable() = true;
2113 track_list_visible_cell->property_radio() = false;
2114 track_list_visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &Mixer_UI::track_visibility_changed));
2116 track_display.signal_button_press_event().connect (sigc::mem_fun (*this, &Mixer_UI::track_display_button_press), false);
2118 track_display_scroller.add (track_display);
2119 track_display_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2121 VBox* v = manage (new VBox);
2123 v->pack_start (track_display_scroller, true, true);
2125 Button* b = manage (new Button);
2127 Widget* w = manage (new Image (Stock::ADD, ICON_SIZE_BUTTON));
2131 b->signal_clicked().connect (sigc::mem_fun (*this, &Mixer_UI::new_track_or_bus));
2133 v->pack_start (*b, false, false);
2135 track_display_frame.set_name("BaseFrame");
2136 track_display_frame.set_shadow_type (Gtk::SHADOW_IN);
2137 track_display_frame.add (*v);
2139 track_display_scroller.show();
2140 track_display_frame.show();
2141 track_display.show();
2145 Mixer_UI::new_track_or_bus ()
2147 ARDOUR_UI::instance()->add_route ();
2151 Mixer_UI::update_title ()
2153 if (!own_window()) {
2160 if (_session->snap_name() != _session->name()) {
2161 n = _session->snap_name ();
2163 n = _session->name ();
2166 if (_session->dirty ()) {
2170 WindowTitle title (n);
2171 title += S_("Window|Mixer");
2172 title += Glib::get_application_name ();
2173 own_window()->set_title (title.get_string());
2177 WindowTitle title (S_("Window|Mixer"));
2178 title += Glib::get_application_name ();
2179 own_window()->set_title (title.get_string());
2184 Mixer_UI::strip_by_x (int x)
2186 for (list<MixerStrip*>::iterator i = strips.begin(); i != strips.end(); ++i) {
2189 (*i)->translate_coordinates (_content, 0, 0, x1, y);
2190 x2 = x1 + (*i)->get_width();
2192 if (x >= x1 && x <= x2) {
2201 Mixer_UI::set_route_targets_for_operation ()
2203 _route_targets.clear ();
2205 if (!_selection.empty()) {
2206 _route_targets = _selection.routes;
2210 // removed "implicit" selections of strips, after discussion on IRC
2215 Mixer_UI::monitor_section_going_away ()
2217 if (_monitor_section) {
2218 monitor_section_detached ();
2219 out_packer.remove (_monitor_section->tearoff());
2220 _monitor_section->set_session (0);
2221 delete _monitor_section;
2222 _monitor_section = 0;
2227 Mixer_UI::toggle_midi_input_active (bool flip_others)
2229 boost::shared_ptr<RouteList> rl (new RouteList);
2232 set_route_targets_for_operation ();
2234 for (RouteUISelection::iterator r = _route_targets.begin(); r != _route_targets.end(); ++r) {
2235 boost::shared_ptr<MidiTrack> mt = (*r)->midi_track();
2238 rl->push_back ((*r)->route());
2239 onoff = !mt->input_active();
2243 _session->set_exclusive_input_active (rl, onoff, flip_others);
2247 Mixer_UI::maximise_mixer_space ()
2249 if (!own_window()) {
2257 _window->fullscreen ();
2262 Mixer_UI::restore_mixer_space ()
2264 if (!own_window()) {
2272 own_window()->unfullscreen();
2277 Mixer_UI::monitor_section_attached ()
2279 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
2280 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2281 act->set_sensitive (true);
2282 tact->set_active ();
2286 Mixer_UI::monitor_section_detached ()
2288 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
2289 act->set_sensitive (false);
2293 Mixer_UI::store_current_favorite_order ()
2295 typedef Gtk::TreeModel::Children type_children;
2296 type_children children = favorite_plugins_model->children();
2297 favorite_order.clear();
2298 for(type_children::iterator iter = children.begin(); iter != children.end(); ++iter)
2300 Gtk::TreeModel::Row row = *iter;
2301 ARDOUR::PluginPresetPtr ppp = row[favorite_plugins_columns.plugin];
2302 favorite_order.push_back (ppp->_pip);
2303 std::string name = row[favorite_plugins_columns.name];
2304 favorite_ui_state[(*ppp->_pip).unique_id] = favorite_plugins_display.row_expanded (favorite_plugins_model->get_path(iter));
2309 Mixer_UI::save_favorite_ui_state (const TreeModel::iterator& iter, const TreeModel::Path& path)
2311 Gtk::TreeModel::Row row = *iter;
2312 ARDOUR::PluginPresetPtr ppp = row[favorite_plugins_columns.plugin];
2314 favorite_ui_state[(*ppp->_pip).unique_id] = favorite_plugins_display.row_expanded (favorite_plugins_model->get_path(iter));
2318 Mixer_UI::refiller (PluginInfoList& result, const PluginInfoList& plugs)
2320 PluginManager& manager (PluginManager::instance());
2321 for (PluginInfoList::const_iterator i = plugs.begin(); i != plugs.end(); ++i) {
2322 if (manager.get_status (*i) != PluginManager::Favorite) {
2325 result.push_back (*i);
2329 struct PluginCustomSorter {
2331 bool operator() (PluginInfoPtr a, PluginInfoPtr b) const {
2332 PluginInfoList::const_iterator aiter = _user.begin();
2333 PluginInfoList::const_iterator biter = _user.begin();
2334 while (aiter != _user.end()) { if ((*aiter)->unique_id == a->unique_id) { break; } ++aiter; }
2335 while (biter != _user.end()) { if ((*biter)->unique_id == b->unique_id) { break; } ++biter; }
2337 if (aiter != _user.end() && biter != _user.end()) {
2338 return std::distance (_user.begin(), aiter) < std::distance (_user.begin(), biter);
2340 if (aiter != _user.end()) {
2343 if (biter != _user.end()) {
2346 return ARDOUR::cmp_nocase((*a).name, (*b).name) == -1;
2348 PluginCustomSorter(PluginInfoList user) : _user (user) {}
2350 PluginInfoList _user;
2354 Mixer_UI::refill_favorite_plugins ()
2356 PluginInfoList plugs;
2357 PluginManager& mgr (PluginManager::instance());
2360 refiller (plugs, mgr.lv2_plugin_info ());
2362 #ifdef WINDOWS_VST_SUPPORT
2363 refiller (plugs, mgr.windows_vst_plugin_info ());
2365 #ifdef LXVST_SUPPORT
2366 refiller (plugs, mgr.lxvst_plugin_info ());
2368 #ifdef AUDIOUNIT_SUPPORT
2369 refiller (plugs, mgr.au_plugin_info ());
2371 refiller (plugs, mgr.ladspa_plugin_info ());
2372 refiller (plugs, mgr.lua_plugin_info ());
2374 store_current_favorite_order ();
2376 PluginCustomSorter cmp (favorite_order);
2379 favorite_order = plugs;
2381 sync_treeview_from_favorite_order ();
2385 Mixer_UI::sync_treeview_favorite_ui_state (const TreeModel::Path& path, const TreeModel::iterator&)
2388 if (!(iter = favorite_plugins_model->get_iter (path))) {
2391 ARDOUR::PluginPresetPtr ppp = (*iter)[favorite_plugins_columns.plugin];
2395 PluginInfoPtr pip = ppp->_pip;
2396 if (favorite_ui_state.find (pip->unique_id) != favorite_ui_state.end ()) {
2397 if (favorite_ui_state[pip->unique_id]) {
2398 favorite_plugins_display.expand_row (path, true);
2404 Mixer_UI::sync_treeview_from_favorite_order ()
2406 favorite_plugins_model->clear ();
2407 for (PluginInfoList::const_iterator i = favorite_order.begin(); i != favorite_order.end(); ++i) {
2408 PluginInfoPtr pip = (*i);
2410 TreeModel::Row newrow = *(favorite_plugins_model->append());
2411 newrow[favorite_plugins_columns.name] = (*i)->name;
2412 newrow[favorite_plugins_columns.plugin] = PluginPresetPtr (new PluginPreset(pip));
2417 vector<ARDOUR::Plugin::PresetRecord> presets = (*i)->get_presets (true);
2418 for (vector<ARDOUR::Plugin::PresetRecord>::const_iterator j = presets.begin(); j != presets.end(); ++j) {
2419 Gtk::TreeModel::Row child_row = *(favorite_plugins_model->append (newrow.children()));
2420 child_row[favorite_plugins_columns.name] = (*j).label;
2421 child_row[favorite_plugins_columns.plugin] = PluginPresetPtr (new PluginPreset(pip, &(*j)));
2423 if (favorite_ui_state.find (pip->unique_id) != favorite_ui_state.end ()) {
2424 if (favorite_ui_state[pip->unique_id]) {
2425 favorite_plugins_display.expand_row (favorite_plugins_model->get_path(newrow), true);
2432 Mixer_UI::popup_note_context_menu (GdkEventButton *ev)
2434 using namespace Gtk::Menu_Helpers;
2436 Gtk::Menu* m = manage (new Menu);
2437 MenuList& items = m->items ();
2439 if (_selection.routes.empty()) {
2440 items.push_back (MenuElem (_("No Track/Bus is selected.")));
2442 items.push_back (MenuElem (_("Add at the top"),
2443 sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddTop)));
2444 items.push_back (MenuElem (_("Add Pre-Fader"),
2445 sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddPreFader)));
2446 items.push_back (MenuElem (_("Add Post-Fader"),
2447 sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddPostFader)));
2448 items.push_back (MenuElem (_("Add at the end"),
2449 sigc::bind (sigc::mem_fun (*this, &Mixer_UI::add_selected_processor), AddBottom)));
2452 items.push_back (SeparatorElem());
2454 items.push_back (MenuElem (_("Remove from favorites"), sigc::mem_fun (*this, &Mixer_UI::remove_selected_from_favorites)));
2456 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2457 if (ppp && ppp->_preset.valid && ppp->_preset.user) {
2458 // we cannot currently delete AU presets
2459 if (!ppp->_pip || ppp->_pip->type != AudioUnit) {
2460 items.push_back (MenuElem (_("Delete Preset"), sigc::mem_fun (*this, &Mixer_UI::delete_selected_preset)));
2464 m->popup (ev->button, ev->time);
2468 Mixer_UI::plugin_row_button_press (GdkEventButton *ev)
2470 if ((ev->type == GDK_BUTTON_PRESS) && (ev->button == 3) ) {
2471 TreeModel::Path path;
2472 TreeViewColumn* column;
2474 if (favorite_plugins_display.get_path_at_pos ((int)ev->x, (int)ev->y, path, column, cellx, celly)) {
2475 Glib::RefPtr<Gtk::TreeView::Selection> selection = favorite_plugins_display.get_selection();
2477 selection->unselect_all();
2478 selection->select(path);
2481 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2483 popup_note_context_menu (ev);
2491 Mixer_UI::selected_plugin ()
2493 Glib::RefPtr<Gtk::TreeView::Selection> selection = favorite_plugins_display.get_selection();
2495 return PluginPresetPtr();
2497 Gtk::TreeModel::iterator iter = selection->get_selected();
2499 return PluginPresetPtr();
2501 return (*iter)[favorite_plugins_columns.plugin];
2505 Mixer_UI::add_selected_processor (ProcessorPosition pos)
2507 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2509 add_favorite_processor (ppp, pos);
2514 Mixer_UI::delete_selected_preset ()
2519 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2520 if (!ppp || !ppp->_preset.valid || !ppp->_preset.user) {
2523 PluginPtr plugin = ppp->_pip->load (*_session);
2524 plugin->get_presets();
2525 plugin->remove_preset (ppp->_preset.label);
2529 Mixer_UI::remove_selected_from_favorites ()
2531 ARDOUR::PluginPresetPtr ppp = selected_plugin();
2535 PluginManager::PluginStatusType status = PluginManager::Normal;
2536 PluginManager& manager (PluginManager::instance());
2538 manager.set_status (ppp->_pip->type, ppp->_pip->unique_id, status);
2539 manager.save_statuses ();
2543 Mixer_UI::plugin_row_activated (const TreeModel::Path& path, TreeViewColumn* column)
2546 if (!(iter = favorite_plugins_model->get_iter (path))) {
2549 ARDOUR::PluginPresetPtr ppp = (*iter)[favorite_plugins_columns.plugin];
2550 add_favorite_processor (ppp, AddPreFader); // TODO: preference?!
2554 Mixer_UI::add_favorite_processor (ARDOUR::PluginPresetPtr ppp, ProcessorPosition pos)
2556 if (!_session || _selection.routes.empty()) {
2560 PluginInfoPtr pip = ppp->_pip;
2561 for (RouteUISelection::iterator i = _selection.routes.begin(); i != _selection.routes.end(); ++i) {
2562 boost::shared_ptr<ARDOUR::Route> rt = (*i)->route();
2563 if (!rt) { continue; }
2565 PluginPtr p = pip->load (*_session);
2566 if (!p) { continue; }
2568 if (ppp->_preset.valid) {
2569 p->load_preset (ppp->_preset);
2572 Route::ProcessorStreams err;
2573 boost::shared_ptr<Processor> processor (new PluginInsert (*_session, p));
2577 rt->add_processor_by_index (processor, 0, &err, Config->get_new_plugins_active ());
2580 rt->add_processor (processor, PreFader, &err, Config->get_new_plugins_active ());
2587 boost::shared_ptr<Processor> np = rt->nth_processor (idx);
2591 if (!np->display_to_user()) {
2594 if (boost::dynamic_pointer_cast<Amp> (np) && // Fader, not Trim
2595 boost::dynamic_pointer_cast<Amp> (np)->gain_control()->parameter().type() == GainAutomation) {
2600 rt->add_processor_by_index (processor, ++pos, &err, Config->get_new_plugins_active ());
2604 rt->add_processor_by_index (processor, -1, &err, Config->get_new_plugins_active ());
2611 PluginTreeStore::row_drop_possible_vfunc(const Gtk::TreeModel::Path& dest, const Gtk::SelectionData& data) const
2613 if (data.get_target() != "GTK_TREE_MODEL_ROW") {
2617 // only allow to re-order top-level items
2619 if (TreePath::get_from_selection_data (data, src)) {
2620 if (src.up() && src.up()) {
2625 // don't allow to drop as child-rows.
2626 Gtk::TreeModel::Path _dest = dest; // un const
2627 const bool is_child = _dest.up (); // explicit bool for clang
2628 if (!is_child || _dest.empty ()) {
2635 Mixer_UI::plugin_drop (const Glib::RefPtr<Gdk::DragContext>&, const Gtk::SelectionData& data)
2637 if (data.get_target() != "PluginPresetPtr") {
2640 if (data.get_length() != sizeof (PluginPresetPtr)) {
2643 const void *d = data.get_data();
2644 const PluginPresetPtr ppp = *(static_cast<const PluginPresetPtr*> (d));
2646 PluginManager::PluginStatusType status = PluginManager::Favorite;
2647 PluginManager& manager (PluginManager::instance());
2649 manager.set_status (ppp->_pip->type, ppp->_pip->unique_id, status);
2650 manager.save_statuses ();
2654 Mixer_UI::do_vca_assign (boost::shared_ptr<VCA> vca)
2656 /* call protected MixerActor:: method */
2661 Mixer_UI::do_vca_unassign (boost::shared_ptr<VCA> vca)
2663 /* call protected MixerActor:: method */