2 Copyright (C) 2006 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.
29 #include <sigc++/bind.h>
31 #include "pbd/error.h"
32 #include "pbd/stl_delete.h"
33 #include "pbd/whitespace.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/enumwriter.h"
36 #include "pbd/stateful_diff_command.h"
38 #include <gtkmm/menu.h>
39 #include <gtkmm/menuitem.h>
40 #include <gtkmm2ext/gtk_ui.h>
41 #include <gtkmm2ext/selector.h>
42 #include <gtkmm2ext/bindable_button.h>
43 #include <gtkmm2ext/utils.h>
45 #include "ardour/amp.h"
46 #include "ardour/meter.h"
47 #include "ardour/event_type_map.h"
48 #include "ardour/pannable.h"
49 #include "ardour/panner.h"
50 #include "ardour/processor.h"
51 #include "ardour/profile.h"
52 #include "ardour/route_group.h"
53 #include "ardour/session.h"
54 #include "ardour/session_playlists.h"
56 #include "evoral/Parameter.hpp"
58 #include "canvas/debug.h"
60 #include "ardour_ui.h"
61 #include "ardour_button.h"
62 #include "audio_streamview.h"
64 #include "enums_convert.h"
65 #include "route_time_axis.h"
66 #include "automation_time_axis.h"
68 #include "gui_thread.h"
69 #include "item_counts.h"
71 #include "paste_context.h"
72 #include "playlist_selector.h"
73 #include "point_selection.h"
75 #include "public_editor.h"
76 #include "region_view.h"
77 #include "rgb_macros.h"
78 #include "selection.h"
79 #include "streamview.h"
81 #include "ui_config.h"
83 #include "route_group_menu.h"
85 #include "ardour/track.h"
89 using namespace ARDOUR;
90 using namespace ARDOUR_UI_UTILS;
92 using namespace Gtkmm2ext;
94 using namespace Editing;
98 RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
100 , StripableTimeAxisView(ed, sess, canvas)
102 , button_table (3, 3)
103 , route_group_button (S_("RTAV|G"))
104 , playlist_button (S_("RTAV|P"))
105 , automation_button (S_("RTAV|A"))
106 , automation_action_menu (0)
107 , plugins_submenu_item (0)
108 , route_group_menu (0)
109 , playlist_action_menu (0)
111 , color_mode_menu (0)
112 , gm (sess, true, 75, 14)
113 , _ignore_set_layer_display (false)
114 , pan_automation_item(NULL)
116 number_label.set_name("tracknumber label");
117 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
118 number_label.set_alignment(.5, .5);
119 number_label.set_fallthrough_to_parent (true);
121 sess->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::parameter_changed, this, _1), gui_context());
122 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::parameter_changed));
124 parameter_changed ("editor-stereo-only-meters");
128 RouteTimeAxisView::route_property_changed (const PBD::PropertyChange& what_changed)
130 if (what_changed.contains (ARDOUR::Properties::name)) {
136 RouteTimeAxisView::set_route (boost::shared_ptr<Route> rt)
138 RouteUI::set_route (rt);
139 StripableTimeAxisView::set_stripable (rt);
141 CANVAS_DEBUG_NAME (_canvas_display, string_compose ("main for %1", rt->name()));
142 CANVAS_DEBUG_NAME (selection_group, string_compose ("selections for %1", rt->name()));
143 CANVAS_DEBUG_NAME (_ghost_group, string_compose ("ghosts for %1", rt->name()));
146 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
149 gm.set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
150 gm.get_level_meter().set_no_show_all();
151 gm.get_level_meter().setup_meters(50, meter_width);
152 gm.update_gain_sensitive ();
155 if (get_gui_property ("height", height)) {
158 set_height (preset_height (HeightNormal));
161 if (!_route->is_auditioner()) {
162 if (gui_property ("visible").empty()) {
163 set_gui_property ("visible", true);
166 set_gui_property ("visible", false);
169 timestretch_rect = 0;
172 ignore_toggle = false;
174 route_group_button.set_name ("route button");
175 playlist_button.set_name ("route button");
176 automation_button.set_name ("route button");
178 route_group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::route_group_click), false);
179 playlist_button.signal_button_press_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::playlist_click), false);
180 automation_button.signal_button_press_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::automation_click), false);
184 if (ARDOUR::Profile->get_mixbus()) {
185 controls_table.attach (*rec_enable_button, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
187 controls_table.attach (*rec_enable_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
190 if (is_midi_track()) {
191 set_tooltip(*rec_enable_button, _("Record (Right-click for Step Edit)"));
192 gm.set_fader_name ("MidiTrackFader");
194 set_tooltip(*rec_enable_button, _("Record"));
195 gm.set_fader_name ("AudioTrackFader");
198 /* set playlist button tip to the current playlist, and make it update when it changes */
199 update_playlist_tip ();
200 track()->PlaylistChanged.connect (*this, invalidator (*this), ui_bind(&RouteTimeAxisView::update_playlist_tip, this), gui_context());
203 gm.set_fader_name ("AudioBusFader");
204 Gtk::Fixed *blank = manage(new Gtk::Fixed());
205 controls_button_size_group->add_widget(*blank);
206 if (ARDOUR::Profile->get_mixbus() ) {
207 controls_table.attach (*blank, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
209 controls_table.attach (*blank, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
214 top_hbox.pack_end(gm.get_level_meter(), false, false, 2);
216 if (!ARDOUR::Profile->get_mixbus()) {
217 controls_meters_size_group->add_widget (gm.get_level_meter());
220 if (_route->is_master()) {
221 route_group_button.set_sensitive(false);
224 _route->meter_change.connect (*this, invalidator (*this), bind (&RouteTimeAxisView::meter_changed, this), gui_context());
225 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
226 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
227 _route->track_number_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::label_view, this), gui_context());
229 if (ARDOUR::Profile->get_mixbus()) {
230 controls_table.attach (*mute_button, 1, 2, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
232 controls_table.attach (*mute_button, 3, 4, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
234 // mute button is always present, it is used to
235 // force the 'blank' placeholders to the proper size
236 controls_button_size_group->add_widget(*mute_button);
238 if (!_route->is_master()) {
239 if (ARDOUR::Profile->get_mixbus()) {
240 controls_table.attach (*solo_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
242 controls_table.attach (*solo_button, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
245 Gtk::Fixed *blank = manage(new Gtk::Fixed());
246 controls_button_size_group->add_widget(*blank);
247 if (ARDOUR::Profile->get_mixbus()) {
248 controls_table.attach (*blank, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
250 controls_table.attach (*blank, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
255 if (ARDOUR::Profile->get_mixbus()) {
256 controls_table.attach (route_group_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
257 controls_table.attach (gm.get_gain_slider(), 3, 5, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0);
259 else if (!ARDOUR::Profile->get_trx()) {
260 controls_table.attach (route_group_button, 4, 5, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
261 controls_table.attach (gm.get_gain_slider(), 0, 2, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0);
264 set_tooltip(*solo_button,_("Solo"));
265 set_tooltip(*mute_button,_("Mute"));
266 set_tooltip(route_group_button, _("Route Group"));
268 mute_button->set_tweaks(ArdourButton::TrackHeader);
269 solo_button->set_tweaks(ArdourButton::TrackHeader);
270 rec_enable_button->set_tweaks(ArdourButton::TrackHeader);
271 playlist_button.set_tweaks(ArdourButton::TrackHeader);
272 automation_button.set_tweaks(ArdourButton::TrackHeader);
273 route_group_button.set_tweaks(ArdourButton::TrackHeader);
275 if (is_midi_track()) {
276 set_tooltip(automation_button, _("MIDI Controllers and Automation"));
278 set_tooltip(automation_button, _("Automation"));
281 update_track_number_visibility();
284 if (ARDOUR::Profile->get_mixbus()) {
285 controls_table.attach (automation_button, 1, 2, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
287 else if (!ARDOUR::Profile->get_trx()) {
288 controls_table.attach (automation_button, 3, 4, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
291 if (is_track() && track()->mode() == ARDOUR::Normal) {
292 if (ARDOUR::Profile->get_mixbus()) {
293 controls_table.attach (playlist_button, 0, 1, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
295 else if (!ARDOUR::Profile->get_trx()) {
296 controls_table.attach (playlist_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
302 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::processors_changed, this, _1), gui_context());
306 LayerDisplay layer_display;
307 if (get_gui_property ("layer-display", layer_display)) {
308 set_layer_display (layer_display);
311 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::map_frozen, this), gui_context());
312 track()->SpeedChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::speed_changed, this), gui_context());
314 /* pick up the correct freeze state */
319 UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::color_handler));
321 PropertyList* plist = new PropertyList();
323 plist->add (ARDOUR::Properties::group_mute, true);
324 plist->add (ARDOUR::Properties::group_solo, true);
326 route_group_menu = new RouteGroupMenu (_session, plist);
328 gm.get_level_meter().signal_scroll_event().connect (sigc::mem_fun (*this, &RouteTimeAxisView::controls_ebox_scroll), false);
331 RouteTimeAxisView::~RouteTimeAxisView ()
333 cleanup_gui_properties ();
335 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
339 delete playlist_action_menu;
340 playlist_action_menu = 0;
345 _automation_tracks.clear ();
347 delete route_group_menu;
348 CatchDeletion (this);
352 RouteTimeAxisView::name() const
355 return _route->name();
361 RouteTimeAxisView::post_construct ()
363 /* map current state of the route */
365 update_diskstream_display ();
366 setup_processor_menu_and_curves ();
367 reset_processor_automation_curves ();
370 /** Set up the processor menu for the current set of processors, and
371 * display automation curves for any parameters which have data.
374 RouteTimeAxisView::setup_processor_menu_and_curves ()
376 _subplugin_menu_map.clear ();
377 subplugin_menu.items().clear ();
378 _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
379 _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
383 RouteTimeAxisView::route_group_click (GdkEventButton *ev)
385 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
386 if (_route->route_group()) {
387 _route->route_group()->remove (_route);
393 r.push_back (route ());
395 route_group_menu->build (r);
396 if (ev->button == 1) {
397 Gtkmm2ext::anchored_menu_popup(route_group_menu->menu(),
401 route_group_menu->menu()->popup (ev->button, ev->time);
408 RouteTimeAxisView::playlist_changed ()
414 RouteTimeAxisView::label_view ()
416 string x = _route->name ();
417 if (x != name_label.get_text ()) {
418 name_label.set_text (x);
420 const int64_t track_number = _route->track_number ();
421 if (track_number == 0) {
422 number_label.set_text ("");
424 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
429 RouteTimeAxisView::update_track_number_visibility ()
432 bool show_label = _session->config.get_track_name_number();
434 if (_route && _route->is_master()) {
438 if (number_label.get_parent()) {
439 controls_table.remove (number_label);
442 if (ARDOUR::Profile->get_mixbus()) {
443 controls_table.attach (number_label, 3, 4, 0, 1, Gtk::SHRINK, Gtk::EXPAND|Gtk::FILL, 1, 0);
445 controls_table.attach (number_label, 0, 1, 0, 1, Gtk::SHRINK, Gtk::EXPAND|Gtk::FILL, 1, 0);
447 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
448 // except the width of the number label is subtracted from the name-hbox, so we
449 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
450 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
452 number_label.set_size_request(tnw, -1);
453 number_label.show ();
455 number_label.hide ();
460 RouteTimeAxisView::parameter_changed (string const & p)
462 if (p == "track-name-number") {
463 update_track_number_visibility();
464 } else if (p == "editor-stereo-only-meters") {
465 if (UIConfiguration::instance().get_editor_stereo_only_meters()) {
466 gm.get_level_meter().set_max_audio_meter_count (2);
468 gm.get_level_meter().set_max_audio_meter_count (0);
474 RouteTimeAxisView::take_name_changed (void *src)
482 RouteTimeAxisView::playlist_click (GdkEventButton *ev)
484 if (ev->button != 1) {
488 build_playlist_menu ();
489 conditionally_add_to_selection ();
490 Gtkmm2ext::anchored_menu_popup(playlist_action_menu, &playlist_button,
496 RouteTimeAxisView::automation_click (GdkEventButton *ev)
498 if (ev->button != 1) {
502 conditionally_add_to_selection ();
503 build_automation_action_menu (false);
504 Gtkmm2ext::anchored_menu_popup(automation_action_menu, &automation_button,
510 RouteTimeAxisView::build_automation_action_menu (bool for_selection)
512 using namespace Menu_Helpers;
514 /* detach subplugin_menu from automation_action_menu before we delete automation_action_menu,
515 otherwise bad things happen (see comment for similar case in MidiTimeAxisView::build_automation_action_menu)
518 detach_menu (subplugin_menu);
520 _main_automation_menu_map.clear ();
521 delete automation_action_menu;
522 automation_action_menu = new Menu;
524 MenuList& items = automation_action_menu->items();
526 automation_action_menu->set_name ("ArdourContextMenu");
528 items.push_back (MenuElem (_("Show All Automation"),
529 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::show_all_automation), for_selection)));
531 items.push_back (MenuElem (_("Show Existing Automation"),
532 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::show_existing_automation), for_selection)));
534 items.push_back (MenuElem (_("Hide All Automation"),
535 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::hide_all_automation), for_selection)));
537 /* Attach the plugin submenu. It may have previously been used elsewhere,
538 so it was detached above
541 bool single_track_selected = (!for_selection || _editor.get_selection().tracks.size() == 1);
543 if (!subplugin_menu.items().empty()) {
544 items.push_back (SeparatorElem ());
545 items.push_back (MenuElem (_("Processor automation"), subplugin_menu));
546 items.back().set_sensitive (single_track_selected);
549 /* Add any route automation */
552 items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &RouteTimeAxisView::update_gain_track_visibility)));
553 gain_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
554 gain_automation_item->set_active (single_track_selected &&
555 string_to<bool>(gain_track->gui_property ("visible")));
557 _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
561 items.push_back (CheckMenuElem (_("Trim"), sigc::mem_fun (*this, &RouteTimeAxisView::update_trim_track_visibility)));
562 trim_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
563 trim_automation_item->set_active (single_track_selected &&
564 string_to<bool>(trim_track->gui_property ("visible")));
566 _main_automation_menu_map[Evoral::Parameter(TrimAutomation)] = trim_automation_item;
570 items.push_back (CheckMenuElem (_("Mute"), sigc::mem_fun (*this, &RouteTimeAxisView::update_mute_track_visibility)));
571 mute_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
572 mute_automation_item->set_active (single_track_selected &&
573 string_to<bool>(mute_track->gui_property ("visible")));
575 _main_automation_menu_map[Evoral::Parameter(MuteAutomation)] = mute_automation_item;
578 if (!pan_tracks.empty() && !ARDOUR::Profile->get_mixbus()) {
579 items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &RouteTimeAxisView::update_pan_track_visibility)));
580 pan_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
581 pan_automation_item->set_active (single_track_selected &&
582 string_to<bool>(pan_tracks.front()->gui_property ("visible")));
584 set<Evoral::Parameter> const & params = _route->pannable()->what_can_be_automated ();
585 for (set<Evoral::Parameter>::const_iterator p = params.begin(); p != params.end(); ++p) {
586 _main_automation_menu_map[*p] = pan_automation_item;
592 RouteTimeAxisView::build_display_menu ()
594 using namespace Menu_Helpers;
598 TimeAxisView::build_display_menu ();
600 /* now fill it with our stuff */
602 MenuList& items = display_menu->items();
603 display_menu->set_name ("ArdourContextMenu");
605 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
607 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
609 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
611 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
613 items.push_back (SeparatorElem());
616 detach_menu (*_size_menu);
619 items.push_back (MenuElem (_("Height"), *_size_menu));
620 items.push_back (SeparatorElem());
622 // Hook for derived classes to add type specific stuff
623 append_extra_display_menu_items ();
627 Menu* layers_menu = manage (new Menu);
628 MenuList &layers_items = layers_menu->items();
629 layers_menu->set_name("ArdourContextMenu");
631 RadioMenuItem::Group layers_group;
633 /* Find out how many overlaid/stacked tracks we have in the selection */
637 int unchangeable = 0;
638 TrackSelection const & s = _editor.get_selection().tracks;
640 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
641 StreamView* v = (*i)->view ();
646 if (v->can_change_layer_display()) {
647 switch (v->layer_display ()) {
661 /* We're not connecting to signal_toggled() here; in the case where these two items are
662 set to be in the `inconsistent' state, it seems that one or other will end up active
663 as well as inconsistent (presumably due to the RadioMenuItem::Group). Then when you
664 select the active one, no toggled signal is emitted so nothing happens.
667 _ignore_set_layer_display = true;
669 layers_items.push_back (RadioMenuElem (layers_group, _("Overlaid")));
670 RadioMenuItem* i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
671 i->set_active (overlaid != 0 && stacked == 0);
672 i->set_inconsistent (overlaid != 0 && stacked != 0);
673 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Overlaid, true));
676 i->set_sensitive (false);
679 layers_items.push_back (RadioMenuElem (layers_group, _("Stacked")));
680 i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
681 i->set_active (overlaid == 0 && stacked != 0);
682 i->set_inconsistent (overlaid != 0 && stacked != 0);
683 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true));
686 i->set_sensitive (false);
689 _ignore_set_layer_display = false;
691 items.push_back (MenuElem (_("Layers"), *layers_menu));
693 Menu* alignment_menu = manage (new Menu);
694 MenuList& alignment_items = alignment_menu->items();
695 alignment_menu->set_name ("ArdourContextMenu");
697 RadioMenuItem::Group align_group;
699 /* Same verbose hacks as for the layering options above */
705 boost::shared_ptr<Track> first_track;
707 for (TrackSelection::const_iterator t = s.begin(); t != s.end(); ++t) {
708 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*t);
709 if (!r || !r->is_track ()) {
714 first_track = r->track();
717 switch (r->track()->alignment_choice()) {
721 switch (r->track()->alignment_style()) {
722 case ExistingMaterial:
730 case UseExistingMaterial:
746 inconsistent = false;
753 if (!inconsistent && first_track) {
755 alignment_items.push_back (RadioMenuElem (align_group, _("Automatic (based on I/O connections)")));
756 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
757 i->set_active (automatic != 0 && existing == 0 && capture == 0);
758 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, Automatic, true));
760 switch (first_track->alignment_choice()) {
762 switch (first_track->alignment_style()) {
763 case ExistingMaterial:
764 alignment_items.push_back (MenuElem (_("(Currently: Existing Material)")));
767 alignment_items.push_back (MenuElem (_("(Currently: Capture Time)")));
775 alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material")));
776 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
777 i->set_active (existing != 0 && capture == 0 && automatic == 0);
778 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseExistingMaterial, true));
780 alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time")));
781 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
782 i->set_active (existing == 0 && capture != 0 && automatic == 0);
783 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseCaptureTime, true));
785 items.push_back (MenuElem (_("Alignment"), *alignment_menu));
791 #ifdef XXX_OLD_DESTRUCTIVE_API_XXX
792 Menu* mode_menu = manage (new Menu);
793 MenuList& mode_items = mode_menu->items ();
794 mode_menu->set_name ("ArdourContextMenu");
796 RadioMenuItem::Group mode_group;
802 for (TrackSelection::const_iterator t = s.begin(); t != s.end(); ++t) {
803 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*t);
804 if (!r || !r->is_track ()) {
808 switch (r->track()->mode()) {
821 mode_items.push_back (RadioMenuElem (mode_group, _("Normal Mode")));
822 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
823 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Normal, true));
824 i->set_active (normal != 0 && tape == 0 && non_layered == 0);
825 i->set_inconsistent (normal != 0 && (tape != 0 || non_layered != 0));
827 mode_items.push_back (RadioMenuElem (mode_group, _("Tape Mode")));
828 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
829 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Destructive, true));
830 i->set_active (normal == 0 && tape != 0 && non_layered == 0);
831 i->set_inconsistent (tape != 0 && (normal != 0 || non_layered != 0));
833 mode_items.push_back (RadioMenuElem (mode_group, _("Non-Layered Mode")));
834 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
835 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::NonLayered, true));
836 i->set_active (normal == 0 && tape == 0 && non_layered != 0);
837 i->set_inconsistent (non_layered != 0 && (normal != 0 || tape != 0));
839 items.push_back (MenuElem (_("Record Mode"), *mode_menu));
842 items.push_back (SeparatorElem());
844 build_playlist_menu ();
845 items.push_back (MenuElem (_("Playlist"), *playlist_action_menu));
846 items.back().set_sensitive (_editor.get_selection().tracks.size() <= 1);
849 route_group_menu->detach ();
852 for (TrackSelection::iterator i = _editor.get_selection().tracks.begin(); i != _editor.get_selection().tracks.end(); ++i) {
853 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
855 r.push_back (rtv->route ());
860 r.push_back (route ());
863 if (!_route->is_master()) {
864 route_group_menu->build (r);
865 items.push_back (MenuElem (_("Group"), *route_group_menu->menu ()));
868 build_automation_action_menu (true);
869 items.push_back (MenuElem (_("Automation"), *automation_action_menu));
871 items.push_back (SeparatorElem());
875 TrackSelection const & s = _editor.get_selection().tracks;
876 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
877 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
882 if (r->route()->active()) {
889 items.push_back (CheckMenuElem (_("Active")));
890 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
891 bool click_sets_active = true;
892 if (active > 0 && inactive == 0) {
893 i->set_active (true);
894 click_sets_active = false;
895 } else if (active > 0 && inactive > 0) {
896 i->set_inconsistent (true);
898 i->set_sensitive(! _session->transport_rolling());
899 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), click_sets_active, true));
901 items.push_back (SeparatorElem());
902 items.push_back (MenuElem (_("Hide"), sigc::bind (sigc::mem_fun(_editor, &PublicEditor::hide_track_in_display), this, true)));
903 if (_route && !_route->is_master()) {
904 items.push_back (SeparatorElem());
905 items.push_back (MenuElem (_("Duplicate..."), boost::bind (&ARDOUR_UI::start_duplicate_routes, ARDOUR_UI::instance())));
907 items.push_back (SeparatorElem());
908 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(_editor, &PublicEditor::remove_tracks)));
911 #ifdef XXX_OLD_DESTRUCTIVE_API_XXX
913 RouteTimeAxisView::set_track_mode (TrackMode mode, bool apply_to_selection)
915 if (apply_to_selection) {
916 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_track_mode, _1, mode, false));
919 bool needs_bounce = false;
921 if (!track()->can_use_mode (mode, needs_bounce)) {
927 cerr << "would bounce this one\n";
932 track()->set_mode (mode);
938 RouteTimeAxisView::show_timestretch (framepos_t start, framepos_t end, int layers, int layer)
940 TimeAxisView::show_timestretch (start, end, layers, layer);
950 /* check that the time selection was made in our route, or our route group.
951 remember that route_group() == 0 implies the route is *not* in a edit group.
954 if (!(ts.track == this || (ts.group != 0 && ts.group == _route->route_group()))) {
955 /* this doesn't apply to us */
959 /* ignore it if our edit group is not active */
961 if ((ts.track != this) && _route->route_group() && !_route->route_group()->is_active()) {
966 if (timestretch_rect == 0) {
967 timestretch_rect = new ArdourCanvas::Rectangle (canvas_display ());
968 timestretch_rect->set_fill_color (ArdourCanvas::HSV (UIConfiguration::instance().color ("time stretch fill")).mod (UIConfiguration::instance().modifier ("time stretch fill")).color());
969 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
972 timestretch_rect->show ();
973 timestretch_rect->raise_to_top ();
975 double const x1 = start / _editor.get_current_zoom();
976 double const x2 = (end - 1) / _editor.get_current_zoom();
978 timestretch_rect->set (ArdourCanvas::Rect (x1, current_height() * (layers - layer - 1) / layers,
979 x2, current_height() * (layers - layer) / layers));
983 RouteTimeAxisView::hide_timestretch ()
985 TimeAxisView::hide_timestretch ();
987 if (timestretch_rect) {
988 timestretch_rect->hide ();
993 RouteTimeAxisView::show_selection (TimeSelection& ts)
997 /* ignore it if our edit group is not active or if the selection was started
998 in some other track or route group (remember that route_group() == 0 means
999 that the track is not in an route group).
1002 if (((ts.track != this && !is_child (ts.track)) && _route->route_group() && !_route->route_group()->is_active()) ||
1003 (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route->route_group())))) {
1009 TimeAxisView::show_selection (ts);
1013 RouteTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
1016 bool height_changed = (height == 0) || (h != height);
1018 int meter_width = 3;
1019 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
1022 gm.get_level_meter().setup_meters (gmlen, meter_width);
1024 TimeAxisView::set_height (h, m);
1027 _view->set_height ((double) current_height());
1030 if (height >= preset_height (HeightNormal)) {
1034 gm.get_gain_slider().show();
1035 mute_button->show();
1036 if (!_route || _route->is_monitor()) {
1037 solo_button->hide();
1039 solo_button->show();
1041 if (rec_enable_button)
1042 rec_enable_button->show();
1044 route_group_button.show();
1045 automation_button.show();
1047 if (is_track() && track()->mode() == ARDOUR::Normal) {
1048 playlist_button.show();
1055 gm.get_gain_slider().hide();
1056 mute_button->show();
1057 if (!_route || _route->is_monitor()) {
1058 solo_button->hide();
1060 solo_button->show();
1062 if (rec_enable_button)
1063 rec_enable_button->show();
1065 route_group_button.hide ();
1066 automation_button.hide ();
1068 if (is_track() && track()->mode() == ARDOUR::Normal) {
1069 playlist_button.hide ();
1074 if (height_changed && !no_redraw) {
1075 /* only emit the signal if the height really changed */
1081 RouteTimeAxisView::route_color_changed ()
1084 _view->apply_color (color(), StreamView::RegionColor);
1087 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1091 RouteTimeAxisView::set_samples_per_pixel (double fpp)
1096 speed = track()->speed();
1100 _view->set_samples_per_pixel (fpp * speed);
1103 StripableTimeAxisView::set_samples_per_pixel (fpp * speed);
1107 RouteTimeAxisView::set_align_choice (RadioMenuItem* mitem, AlignChoice choice, bool apply_to_selection)
1109 if (!mitem->get_active()) {
1110 /* this is one of the two calls made when these radio menu items change status. this one
1111 is for the item that became inactive, and we want to ignore it.
1116 if (apply_to_selection) {
1117 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_align_choice, _1, mitem, choice, false));
1120 track()->set_align_choice (choice);
1126 RouteTimeAxisView::rename_current_playlist ()
1128 ArdourPrompter prompter (true);
1131 boost::shared_ptr<Track> tr = track();
1132 if (!tr || tr->destructive()) {
1136 boost::shared_ptr<Playlist> pl = tr->playlist();
1141 prompter.set_title (_("Rename Playlist"));
1142 prompter.set_prompt (_("New name for playlist:"));
1143 prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1144 prompter.set_initial_text (pl->name());
1145 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1148 if (prompter.run () != Gtk::RESPONSE_ACCEPT) {
1151 prompter.get_result (name);
1152 if (name.length()) {
1153 if (_session->playlists->by_name (name)) {
1154 MessageDialog msg (_("Given playlist name is not unique."));
1156 prompter.set_initial_text (Playlist::bump_name (name, *_session));
1158 pl->set_name (name);
1166 RouteTimeAxisView::resolve_new_group_playlist_name(std::string &basename, vector<boost::shared_ptr<Playlist> > const & playlists)
1168 std::string ret (basename);
1170 std::string const group_string = "." + route_group()->name() + ".";
1172 // iterate through all playlists
1174 for (vector<boost::shared_ptr<Playlist> >::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1175 std::string tmp = (*i)->name();
1177 std::string::size_type idx = tmp.find(group_string);
1178 // find those which belong to this group
1179 if (idx != string::npos) {
1180 tmp = tmp.substr(idx + group_string.length());
1182 // and find the largest current number
1184 if (x > maxnumber) {
1193 snprintf (buf, sizeof(buf), "%d", maxnumber);
1195 ret = this->name() + "." + route_group()->name () + "." + buf;
1201 RouteTimeAxisView::use_new_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op, bool copy)
1205 boost::shared_ptr<Track> tr = track ();
1206 if (!tr || tr->destructive()) {
1210 boost::shared_ptr<const Playlist> pl = tr->playlist();
1217 if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1218 name = resolve_new_group_playlist_name(name,playlists_before_op);
1221 while (_session->playlists->by_name(name)) {
1222 name = Playlist::bump_name (name, *_session);
1226 // TODO: The prompter "new" button should be de-activated if the user
1227 // specifies a playlist name which already exists in the session.
1229 ArdourPrompter prompter (true);
1232 prompter.set_title (_("New Copy Playlist"));
1233 prompter.set_prompt (_("Name for playlist copy:"));
1235 prompter.set_title (_("New Playlist"));
1236 prompter.set_prompt (_("Name for new playlist:"));
1238 prompter.set_initial_text (name);
1239 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1240 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1241 prompter.show_all ();
1244 if (prompter.run () != Gtk::RESPONSE_ACCEPT) {
1247 prompter.get_result (name);
1248 if (name.length()) {
1249 if (_session->playlists->by_name (name)) {
1250 MessageDialog msg (_("Given playlist name is not unique."));
1252 prompter.set_initial_text (Playlist::bump_name (name, *_session));
1260 if (name.length()) {
1262 tr->use_copy_playlist ();
1264 tr->use_new_playlist ();
1266 tr->playlist()->set_name (name);
1271 RouteTimeAxisView::clear_playlist ()
1273 boost::shared_ptr<Track> tr = track ();
1274 if (!tr || tr->destructive()) {
1278 boost::shared_ptr<Playlist> pl = tr->playlist();
1283 _editor.clear_playlist (pl);
1287 RouteTimeAxisView::speed_changed ()
1289 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&RouteTimeAxisView::reset_samples_per_pixel, this));
1293 RouteTimeAxisView::update_diskstream_display ()
1303 RouteTimeAxisView::selection_click (GdkEventButton* ev)
1305 if (Keyboard::modifier_state_equals (ev->state, (Keyboard::TertiaryModifier|Keyboard::PrimaryModifier))) {
1307 /* special case: select/deselect all tracks */
1309 _editor.begin_reversible_selection_op (X_("Selection Click"));
1311 if (_editor.get_selection().selected (this)) {
1312 _editor.get_selection().clear_tracks ();
1314 _editor.select_all_tracks ();
1317 _editor.commit_reversible_selection_op ();
1322 _editor.begin_reversible_selection_op (X_("Selection Click"));
1324 switch (ArdourKeyboard::selection_type (ev->state)) {
1325 case Selection::Toggle:
1326 _editor.get_selection().toggle (this);
1329 case Selection::Set:
1330 _editor.get_selection().set (this);
1333 case Selection::Extend:
1334 _editor.extend_selection_to_track (*this);
1337 case Selection::Add:
1338 _editor.get_selection().add (this);
1342 _editor.commit_reversible_selection_op ();
1346 RouteTimeAxisView::set_selected_points (PointSelection& points)
1348 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1349 (*i)->set_selected_points (points);
1351 AudioStreamView* asv = dynamic_cast<AudioStreamView*>(_view);
1353 asv->set_selected_points (points);
1358 RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
1361 _view->set_selected_regionviews (regions);
1365 /** Add the selectable things that we have to a list.
1366 * @param results List to add things to.
1369 RouteTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results, bool within)
1374 speed = track()->speed();
1377 framepos_t const start_adjusted = session_frame_to_track_frame(start, speed);
1378 framepos_t const end_adjusted = session_frame_to_track_frame(end, speed);
1380 if ((_view && ((top < 0.0 && bot < 0.0))) || touched (top, bot)) {
1381 _view->get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
1384 /* pick up visible automation tracks */
1386 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1387 if (!(*i)->hidden()) {
1388 (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
1394 RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
1397 _view->get_inverted_selectables (sel, results);
1400 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1401 if (!(*i)->hidden()) {
1402 (*i)->get_inverted_selectables (sel, results);
1410 RouteTimeAxisView::route_group () const
1412 return _route->route_group();
1415 boost::shared_ptr<Playlist>
1416 RouteTimeAxisView::playlist () const
1418 boost::shared_ptr<Track> tr;
1420 if ((tr = track()) != 0) {
1421 return tr->playlist();
1423 return boost::shared_ptr<Playlist> ();
1428 RouteTimeAxisView::name_entry_changed (string const& str)
1430 if (str == _route->name()) {
1436 strip_whitespace_edges (x);
1442 if (_session->route_name_internal (x)) {
1443 ARDOUR_UI::instance()->popup_error (string_compose (_("The name \"%1\" is reserved for %2"), x, PROGRAM_NAME));
1445 } else if (RouteUI::verify_new_route_name (x)) {
1446 _route->set_name (x);
1453 boost::shared_ptr<Region>
1454 RouteTimeAxisView::find_next_region (framepos_t pos, RegionPoint point, int32_t dir)
1456 boost::shared_ptr<Playlist> pl = playlist ();
1459 return pl->find_next_region (pos, point, dir);
1462 return boost::shared_ptr<Region> ();
1466 RouteTimeAxisView::find_next_region_boundary (framepos_t pos, int32_t dir)
1468 boost::shared_ptr<Playlist> pl = playlist ();
1471 return pl->find_next_region_boundary (pos, dir);
1478 RouteTimeAxisView::fade_range (TimeSelection& selection)
1480 boost::shared_ptr<Playlist> what_we_got;
1481 boost::shared_ptr<Track> tr = track ();
1482 boost::shared_ptr<Playlist> playlist;
1485 /* route is a bus, not a track */
1489 playlist = tr->playlist();
1491 TimeSelection time (selection);
1492 float const speed = tr->speed();
1493 if (speed != 1.0f) {
1494 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1495 (*i).start = session_frame_to_track_frame((*i).start, speed);
1496 (*i).end = session_frame_to_track_frame((*i).end, speed);
1500 playlist->clear_changes ();
1501 playlist->clear_owned_changes ();
1503 playlist->fade_range (time);
1505 vector<Command*> cmds;
1506 playlist->rdiff (cmds);
1507 _session->add_commands (cmds);
1508 _session->add_command (new StatefulDiffCommand (playlist));
1513 RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
1515 boost::shared_ptr<Playlist> what_we_got;
1516 boost::shared_ptr<Track> tr = track ();
1517 boost::shared_ptr<Playlist> playlist;
1520 /* route is a bus, not a track */
1524 playlist = tr->playlist();
1526 TimeSelection time (selection.time);
1527 float const speed = tr->speed();
1528 if (speed != 1.0f) {
1529 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1530 (*i).start = session_frame_to_track_frame((*i).start, speed);
1531 (*i).end = session_frame_to_track_frame((*i).end, speed);
1535 playlist->clear_changes ();
1536 playlist->clear_owned_changes ();
1540 if (playlist->cut (time) != 0) {
1541 if (Config->get_edit_mode() == Ripple) {
1542 playlist->ripple(time.start(), -time.length(), NULL);
1544 // no need to exclude any regions from rippling here
1546 vector<Command*> cmds;
1547 playlist->rdiff (cmds);
1548 _session->add_commands (cmds);
1550 _session->add_command (new StatefulDiffCommand (playlist));
1555 if ((what_we_got = playlist->cut (time)) != 0) {
1556 _editor.get_cut_buffer().add (what_we_got);
1557 if (Config->get_edit_mode() == Ripple) {
1558 playlist->ripple(time.start(), -time.length(), NULL);
1560 // no need to exclude any regions from rippling here
1562 vector<Command*> cmds;
1563 playlist->rdiff (cmds);
1564 _session->add_commands (cmds);
1566 _session->add_command (new StatefulDiffCommand (playlist));
1570 if ((what_we_got = playlist->copy (time)) != 0) {
1571 _editor.get_cut_buffer().add (what_we_got);
1576 if ((what_we_got = playlist->cut (time)) != 0) {
1577 if (Config->get_edit_mode() == Ripple) {
1578 playlist->ripple(time.start(), -time.length(), NULL);
1580 // no need to exclude any regions from rippling here
1582 vector<Command*> cmds;
1583 playlist->rdiff (cmds);
1584 _session->add_commands (cmds);
1585 _session->add_command (new StatefulDiffCommand (playlist));
1586 what_we_got->release ();
1593 RouteTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1599 boost::shared_ptr<Playlist> pl = playlist ();
1600 const ARDOUR::DataType type = pl->data_type();
1601 PlaylistSelection::const_iterator p = selection.playlists.get_nth(type, ctx.counts.n_playlists(type));
1603 if (p == selection.playlists.end()) {
1606 ctx.counts.increase_n_playlists(type);
1608 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("paste to %1\n", pos));
1610 if (track()->speed() != 1.0f) {
1611 pos = session_frame_to_track_frame (pos, track()->speed());
1612 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("modified paste to %1\n", pos));
1615 /* add multi-paste offset if applicable */
1616 std::pair<framepos_t, framepos_t> extent = (*p)->get_extent();
1617 const framecnt_t duration = extent.second - extent.first;
1618 pos += _editor.get_paste_offset(pos, ctx.count, duration);
1620 pl->clear_changes ();
1621 pl->clear_owned_changes ();
1622 if (Config->get_edit_mode() == Ripple) {
1623 std::pair<framepos_t, framepos_t> extent = (*p)->get_extent_with_endspace();
1624 framecnt_t amount = extent.second - extent.first;
1625 pl->ripple(pos, amount * ctx.times, boost::shared_ptr<Region>());
1627 pl->paste (*p, pos, ctx.times, sub_num);
1629 vector<Command*> cmds;
1631 _session->add_commands (cmds);
1633 _session->add_command (new StatefulDiffCommand (pl));
1639 struct PlaylistSorter {
1640 bool operator() (boost::shared_ptr<Playlist> a, boost::shared_ptr<Playlist> b) const {
1641 return a->sort_id() < b->sort_id();
1646 RouteTimeAxisView::build_playlist_menu ()
1648 using namespace Menu_Helpers;
1654 delete playlist_action_menu;
1655 playlist_action_menu = new Menu;
1656 playlist_action_menu->set_name ("ArdourContextMenu");
1658 MenuList& playlist_items = playlist_action_menu->items();
1659 playlist_action_menu->set_name ("ArdourContextMenu");
1660 playlist_items.clear();
1662 RadioMenuItem::Group playlist_group;
1663 boost::shared_ptr<Track> tr = track ();
1665 vector<boost::shared_ptr<Playlist> > playlists_tr = _session->playlists->playlists_for_track (tr);
1667 /* sort the playlists */
1669 sort (playlists_tr.begin(), playlists_tr.end(), cmp);
1671 /* add the playlists to the menu */
1672 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) {
1673 playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name()));
1674 RadioMenuItem *item = static_cast<RadioMenuItem*>(&playlist_items.back());
1675 item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist), item, boost::weak_ptr<Playlist> (*i)));
1677 if (tr->playlist()->id() == (*i)->id()) {
1682 playlist_items.push_back (SeparatorElem());
1683 playlist_items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
1684 playlist_items.push_back (SeparatorElem());
1686 if (!route_group() || !route_group()->is_active() || !route_group()->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1687 playlist_items.push_back (MenuElem (_("New..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1688 playlist_items.push_back (MenuElem (_("New Copy..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1691 // Use a label which tells the user what is happening
1692 playlist_items.push_back (MenuElem (_("New Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1693 playlist_items.push_back (MenuElem (_("Copy Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1697 playlist_items.push_back (SeparatorElem());
1698 playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::clear_playlists), this)));
1699 playlist_items.push_back (SeparatorElem());
1701 playlist_items.push_back (MenuElem(_("Select from All..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
1705 RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist> wpl)
1707 assert (is_track());
1709 // exit if we were triggered by deactivating the old playlist
1710 if (!item->get_active()) {
1714 boost::shared_ptr<Playlist> pl (wpl.lock());
1720 if (track()->playlist() == pl) {
1721 // exit when use_playlist is called by the creation of the playlist menu
1722 // or the playlist choice is unchanged
1726 track()->use_playlist (pl);
1728 RouteGroup* rg = route_group();
1730 if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1731 std::string group_string = "." + rg->name() + ".";
1733 std::string take_name = pl->name();
1734 std::string::size_type idx = take_name.find(group_string);
1736 if (idx == std::string::npos)
1739 take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
1741 boost::shared_ptr<RouteList> rl (rg->route_list());
1743 for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
1744 if ((*i) == this->route()) {
1748 std::string playlist_name = (*i)->name()+group_string+take_name;
1750 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
1755 if (track->freeze_state() == Track::Frozen) {
1756 /* Don't change playlists of frozen tracks */
1760 boost::shared_ptr<Playlist> ipl = session()->playlists->by_name(playlist_name);
1762 // No playlist for this track for this take yet, make it
1763 track->use_new_playlist();
1764 track->playlist()->set_name(playlist_name);
1766 track->use_playlist(ipl);
1773 RouteTimeAxisView::update_playlist_tip ()
1775 RouteGroup* rg = route_group ();
1776 if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1777 string group_string = "." + rg->name() + ".";
1779 string take_name = track()->playlist()->name();
1780 string::size_type idx = take_name.find(group_string);
1782 if (idx != string::npos) {
1783 /* find the bit containing the take number / name */
1784 take_name = take_name.substr (idx + group_string.length());
1786 /* set the playlist button tooltip to the take name */
1789 string_compose(_("Take: %1.%2"),
1790 Gtkmm2ext::markup_escape_text (rg->name()),
1791 Gtkmm2ext::markup_escape_text (take_name))
1798 /* set the playlist button tooltip to the playlist name */
1799 set_tooltip (playlist_button, _("Playlist") + std::string(": ") + Gtkmm2ext::markup_escape_text (track()->playlist()->name()));
1804 RouteTimeAxisView::show_playlist_selector ()
1806 _editor.playlist_selector().show_for (this);
1810 RouteTimeAxisView::map_frozen ()
1816 ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::map_frozen)
1818 switch (track()->freeze_state()) {
1820 playlist_button.set_sensitive (false);
1823 playlist_button.set_sensitive (true);
1826 RouteUI::map_frozen ();
1830 RouteTimeAxisView::color_handler ()
1832 //case cTimeStretchOutline:
1833 if (timestretch_rect) {
1834 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
1836 //case cTimeStretchFill:
1837 if (timestretch_rect) {
1838 timestretch_rect->set_fill_color (UIConfiguration::instance().color ("time stretch fill"));
1844 /** Toggle an automation track for a fully-specified Parameter (type,channel,id)
1845 * Will add track if necessary.
1848 RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
1850 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1851 Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1854 /* it doesn't exist yet, so we don't care about the button state: just add it */
1855 create_automation_child (param, true);
1858 bool yn = menu->get_active();
1859 bool changed = false;
1861 if ((changed = track->set_marked_for_display (menu->get_active())) && yn) {
1863 /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
1864 will have done that for us.
1867 if (changed && !no_redraw) {
1875 RouteTimeAxisView::update_pan_track_visibility ()
1877 bool const showit = pan_automation_item->get_active();
1878 bool changed = false;
1880 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1881 if ((*i)->set_marked_for_display (showit)) {
1887 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1892 RouteTimeAxisView::ensure_pan_views (bool show)
1894 bool changed = false;
1895 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1897 (*i)->set_marked_for_display (false);
1900 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1904 if (!_route->panner()) {
1908 set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1909 set<Evoral::Parameter>::iterator p;
1911 for (p = params.begin(); p != params.end(); ++p) {
1912 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1914 if (pan_control->parameter().type() == NullAutomation) {
1915 error << "Pan control has NULL automation type!" << endmsg;
1919 if (automation_child (pan_control->parameter ()).get () == 0) {
1921 /* we don't already have an AutomationTimeAxisView for this parameter */
1923 std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
1925 boost::shared_ptr<AutomationTimeAxisView> t (
1926 new AutomationTimeAxisView (_session,
1930 pan_control->parameter (),
1938 pan_tracks.push_back (t);
1939 add_automation_child (*p, t, show);
1941 pan_tracks.push_back (automation_child (pan_control->parameter ()));
1948 RouteTimeAxisView::show_all_automation (bool apply_to_selection)
1950 if (apply_to_selection) {
1951 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_all_automation, _1, false));
1955 StripableTimeAxisView::show_all_automation ();
1957 /* Show processor automation */
1959 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1960 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1961 if ((*ii)->view == 0) {
1962 add_processor_automation_curve ((*i)->processor, (*ii)->what);
1965 (*ii)->menu_item->set_active (true);
1978 RouteTimeAxisView::show_existing_automation (bool apply_to_selection)
1980 if (apply_to_selection) {
1981 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_existing_automation, _1, false));
1985 StripableTimeAxisView::show_existing_automation ();
1987 /* Show processor automation */
1988 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1989 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1990 if ((*i)->processor->control((*ii)->what)->list()->size() > 0) {
1991 (*ii)->menu_item->set_active (true);
2002 RouteTimeAxisView::hide_all_automation (bool apply_to_selection)
2004 if (apply_to_selection) {
2005 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::hide_all_automation, _1, false));
2008 StripableTimeAxisView::hide_all_automation ();
2010 /* Hide processor automation */
2011 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2012 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2013 (*ii)->menu_item->set_active (false);
2023 RouteTimeAxisView::region_view_added (RegionView* rv)
2025 /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
2026 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
2027 boost::shared_ptr<AutomationTimeAxisView> atv;
2029 if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
2034 for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
2035 (*i)->add_ghost(rv);
2039 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
2041 for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
2047 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
2049 parent.remove_processor_automation_node (this);
2053 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
2056 remove_child (pan->view);
2060 RouteTimeAxisView::ProcessorAutomationNode*
2061 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2063 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2065 if ((*i)->processor == processor) {
2067 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2068 if ((*ii)->what == what) {
2078 /** Add an AutomationTimeAxisView to display automation for a processor's parameter */
2080 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2083 ProcessorAutomationNode* pan;
2085 if ((pan = find_processor_automation_node (processor, what)) == 0) {
2086 /* session state may never have been saved with new plugin */
2087 error << _("programming error: ")
2088 << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"),
2089 processor->name(), what.type(), (int) what.channel(), what.id() )
2091 abort(); /*NOTREACHED*/
2099 boost::shared_ptr<AutomationControl> control
2100 = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
2102 pan->view = boost::shared_ptr<AutomationTimeAxisView>(
2103 new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (),
2104 _editor, *this, false, parent_canvas,
2105 processor->describe_parameter (what), processor->name()));
2107 pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
2109 add_automation_child (control->parameter(), pan->view, pan->view->marked_for_display ());
2112 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
2117 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor>)
2120 pan->menu_item->set_active (false);
2129 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
2131 boost::shared_ptr<Processor> processor (p.lock ());
2133 if (!processor || boost::dynamic_pointer_cast<Amp> (processor)) {
2134 /* The Amp processor is a special case and is dealt with separately */
2138 set<Evoral::Parameter> existing;
2140 processor->what_has_data (existing);
2142 for (set<Evoral::Parameter>::iterator i = existing.begin(); i != existing.end(); ++i) {
2144 Evoral::Parameter param (*i);
2145 boost::shared_ptr<AutomationLine> al;
2147 if ((al = find_processor_automation_curve (processor, param)) != 0) {
2150 add_processor_automation_curve (processor, param);
2156 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
2158 boost::shared_ptr<Processor> processor (p.lock ());
2160 if (!processor || !processor->display_to_user ()) {
2164 /* we use this override to veto the Amp processor from the plugin menu,
2165 as its automation lane can be accessed using the special "Fader" menu
2169 if (boost::dynamic_pointer_cast<Amp> (processor) != 0) {
2173 using namespace Menu_Helpers;
2174 ProcessorAutomationInfo *rai;
2175 list<ProcessorAutomationInfo*>::iterator x;
2177 const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
2179 if (automatable.empty()) {
2183 for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
2184 if ((*x)->processor == processor) {
2189 if (x == processor_automation.end()) {
2190 rai = new ProcessorAutomationInfo (processor);
2191 processor_automation.push_back (rai);
2196 /* any older menu was deleted at the top of processors_changed()
2197 when we cleared the subplugin menu.
2200 rai->menu = manage (new Menu);
2201 MenuList& items = rai->menu->items();
2202 rai->menu->set_name ("ArdourContextMenu");
2206 std::set<Evoral::Parameter> has_visible_automation;
2207 AutomationTimeAxisView::what_has_visible_automation (processor, has_visible_automation);
2209 for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2211 ProcessorAutomationNode* pan;
2212 Gtk::CheckMenuItem* mitem;
2214 string name = processor->describe_parameter (*i);
2216 if (name == X_("hidden")) {
2220 items.push_back (CheckMenuElem (name));
2221 mitem = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
2223 _subplugin_menu_map[*i] = mitem;
2225 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2226 mitem->set_active(true);
2229 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2233 pan = new ProcessorAutomationNode (*i, mitem, *this);
2235 rai->lines.push_back (pan);
2239 pan->menu_item = mitem;
2243 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2246 if (items.size() == 0) {
2250 /* add the menu for this processor, because the subplugin
2251 menu is always cleared at the top of processors_changed().
2252 this is the result of some poor design in gtkmm and/or
2256 subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2261 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2262 RouteTimeAxisView::ProcessorAutomationNode* pan)
2264 bool showit = pan->menu_item->get_active();
2265 bool redraw = false;
2267 if (pan->view == 0 && showit) {
2268 add_processor_automation_curve (rai->processor, pan->what);
2272 if (pan->view && pan->view->set_marked_for_display (showit)) {
2276 if (redraw && !no_redraw) {
2282 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2284 if (c.type == RouteProcessorChange::MeterPointChange) {
2285 /* nothing to do if only the meter point has changed */
2289 using namespace Menu_Helpers;
2291 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2292 (*i)->valid = false;
2295 setup_processor_menu_and_curves ();
2297 bool deleted_processor_automation = false;
2299 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2301 list<ProcessorAutomationInfo*>::iterator tmp;
2309 processor_automation.erase (i);
2310 deleted_processor_automation = true;
2317 if (deleted_processor_automation && !no_redraw) {
2322 boost::shared_ptr<AutomationLine>
2323 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2325 ProcessorAutomationNode* pan;
2327 if ((pan = find_processor_automation_node (processor, what)) != 0) {
2333 return boost::shared_ptr<AutomationLine>();
2337 RouteTimeAxisView::reset_processor_automation_curves ()
2339 for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2345 RouteTimeAxisView::can_edit_name () const
2347 /* we do not allow track name changes if it is record enabled
2349 boost::shared_ptr<Track> trk (boost::dynamic_pointer_cast<Track> (_route));
2353 return !trk->rec_enable_control()->get_value();
2357 RouteTimeAxisView::blink_rec_display (bool onoff)
2359 RouteUI::blink_rec_display (onoff);
2363 RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection)
2365 if (_ignore_set_layer_display) {
2369 if (apply_to_selection) {
2370 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false));
2374 _view->set_layer_display (d);
2377 set_gui_property (X_("layer-display"), d);
2382 RouteTimeAxisView::layer_display () const
2385 return _view->layer_display ();
2388 /* we don't know, since we don't have a _view, so just return something */
2393 RouteTimeAxisView::fast_update ()
2395 gm.get_level_meter().update_meters ();
2399 RouteTimeAxisView::hide_meter ()
2402 gm.get_level_meter().hide_meters ();
2406 RouteTimeAxisView::show_meter ()
2412 RouteTimeAxisView::reset_meter ()
2414 if (UIConfiguration::instance().get_show_track_meters()) {
2415 int meter_width = 3;
2416 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
2419 gm.get_level_meter().setup_meters (height - 9, meter_width);
2426 RouteTimeAxisView::clear_meter ()
2428 gm.get_level_meter().clear_meters ();
2432 RouteTimeAxisView::meter_changed ()
2434 ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed)
2436 if (_route && !no_redraw && UIConfiguration::instance().get_show_track_meters()) {
2439 // reset peak when meter point changes
2440 gm.reset_peak_display();
2444 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2447 if (_route && !no_redraw) {
2453 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu)
2455 using namespace Menu_Helpers;
2457 if (!_underlay_streams.empty()) {
2458 MenuList& parent_items = parent_menu->items();
2459 Menu* gs_menu = manage (new Menu);
2460 gs_menu->set_name ("ArdourContextMenu");
2461 MenuList& gs_items = gs_menu->items();
2463 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2465 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2466 gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2467 sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2473 RouteTimeAxisView::set_underlay_state()
2475 if (!underlay_xml_node) {
2479 XMLNodeList nlist = underlay_xml_node->children();
2480 XMLNodeConstIterator niter;
2481 XMLNode *child_node;
2483 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2484 child_node = *niter;
2486 if (child_node->name() != "Underlay") {
2490 XMLProperty const * prop = child_node->property ("id");
2492 PBD::ID id (prop->value());
2494 RouteTimeAxisView* v = _editor.get_route_view_by_route_id (id);
2497 add_underlay(v->view(), false);
2506 RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/)
2512 RouteTimeAxisView& other = v->trackview();
2514 if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2515 if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2516 fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2517 abort(); /*NOTREACHED*/
2520 _underlay_streams.push_back(v);
2521 other._underlay_mirrors.push_back(this);
2523 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2525 #ifdef GUI_OBJECT_STATE_FIX_REQUIRED
2527 if (!underlay_xml_node) {
2528 underlay_xml_node = xml_node->add_child("Underlays");
2531 XMLNode* node = underlay_xml_node->add_child("Underlay");
2532 XMLProperty const * prop = node->add_property("id");
2533 prop->set_value(v->trackview().route()->id().to_s());
2540 RouteTimeAxisView::remove_underlay (StreamView* v)
2546 UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2547 RouteTimeAxisView& other = v->trackview();
2549 if (it != _underlay_streams.end()) {
2550 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2552 if (gm == other._underlay_mirrors.end()) {
2553 fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2554 abort(); /*NOTREACHED*/
2557 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2559 _underlay_streams.erase(it);
2560 other._underlay_mirrors.erase(gm);
2562 if (underlay_xml_node) {
2563 underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2569 RouteTimeAxisView::set_button_names ()
2571 if (_route && _route->solo_safe_control()->solo_safe()) {
2572 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2574 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2576 if (Config->get_solo_control_is_listen_control()) {
2577 switch (Config->get_listen_position()) {
2578 case AfterFaderListen:
2579 solo_button->set_text (S_("AfterFader|A"));
2580 set_tooltip (*solo_button, _("After-fade listen (AFL)"));
2582 case PreFaderListen:
2583 solo_button->set_text (S_("PreFader|P"));
2584 set_tooltip (*solo_button, _("Pre-fade listen (PFL)"));
2588 solo_button->set_text (S_("Solo|S"));
2589 set_tooltip (*solo_button, _("Solo"));
2591 mute_button->set_text (S_("Mute|M"));
2595 RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
2597 Gtk::CheckMenuItem* rv = StripableTimeAxisView::automation_child_menu_item (param);
2602 ParameterMenuMap::iterator i = _subplugin_menu_map.find (param);
2603 if (i != _subplugin_menu_map.end()) {
2611 RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, bool show)
2613 boost::shared_ptr<AutomationControl> c = _route->gain_control();
2615 error << "Route has no gain automation, unable to add automation track view." << endmsg;
2619 gain_track.reset (new AutomationTimeAxisView (_session,
2620 _route, _route->amp(), c, param,
2625 _route->amp()->describe_parameter(param)));
2628 _view->foreach_regionview (sigc::mem_fun (*gain_track.get(), &TimeAxisView::add_ghost));
2631 add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
2635 RouteTimeAxisView::create_trim_automation_child (const Evoral::Parameter& param, bool show)
2637 boost::shared_ptr<AutomationControl> c = _route->trim()->gain_control();
2638 if (!c || ! _route->trim()->active()) {
2642 trim_track.reset (new AutomationTimeAxisView (_session,
2643 _route, _route->trim(), c, param,
2648 _route->trim()->describe_parameter(param)));
2651 _view->foreach_regionview (sigc::mem_fun (*trim_track.get(), &TimeAxisView::add_ghost));
2654 add_automation_child (Evoral::Parameter(TrimAutomation), trim_track, show);
2658 RouteTimeAxisView::create_mute_automation_child (const Evoral::Parameter& param, bool show)
2660 boost::shared_ptr<AutomationControl> c = _route->mute_control();
2662 error << "Route has no mute automation, unable to add automation track view." << endmsg;
2666 mute_track.reset (new AutomationTimeAxisView (_session,
2667 _route, _route, c, param,
2672 _route->describe_parameter(param)));
2675 _view->foreach_regionview (sigc::mem_fun (*mute_track.get(), &TimeAxisView::add_ghost));
2678 add_automation_child (Evoral::Parameter(MuteAutomation), mute_track, show);
2682 void add_region_to_list (RegionView* rv, RegionList* l)
2684 l->push_back (rv->region());
2688 RouteTimeAxisView::combine_regions ()
2690 /* as of may 2011, we do not offer uncombine for MIDI tracks
2693 if (!is_audio_track()) {
2701 RegionList selected_regions;
2702 boost::shared_ptr<Playlist> playlist = track()->playlist();
2704 _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2706 if (selected_regions.size() < 2) {
2710 playlist->clear_changes ();
2711 boost::shared_ptr<Region> compound_region = playlist->combine (selected_regions);
2713 _session->add_command (new StatefulDiffCommand (playlist));
2714 /* make the new region be selected */
2716 return _view->find_view (compound_region);
2720 RouteTimeAxisView::uncombine_regions ()
2722 /* as of may 2011, we do not offer uncombine for MIDI tracks
2724 if (!is_audio_track()) {
2732 RegionList selected_regions;
2733 boost::shared_ptr<Playlist> playlist = track()->playlist();
2735 /* have to grab selected regions first because the uncombine is going
2736 * to change that in the middle of the list traverse
2739 _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2741 playlist->clear_changes ();
2743 for (RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) {
2744 playlist->uncombine (*i);
2747 _session->add_command (new StatefulDiffCommand (playlist));
2751 RouteTimeAxisView::state_id() const
2753 return string_compose ("rtav %1", _route->id().to_s());
2758 RouteTimeAxisView::remove_child (boost::shared_ptr<TimeAxisView> c)
2760 TimeAxisView::remove_child (c);
2762 boost::shared_ptr<AutomationTimeAxisView> a = boost::dynamic_pointer_cast<AutomationTimeAxisView> (c);
2764 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2765 if (i->second == a) {
2766 _automation_tracks.erase (i);
2774 RouteTimeAxisView::color () const
2776 return route_color ();
2780 RouteTimeAxisView::marked_for_display () const
2782 return !_route->presentation_info().hidden();
2786 RouteTimeAxisView::set_marked_for_display (bool yn)
2788 return RouteUI::mark_hidden (!yn);