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 <gtkmm/menu.h>
32 #include <gtkmm/menuitem.h>
33 #include <gtkmm/stock.h>
35 #include "pbd/error.h"
36 #include "pbd/stl_delete.h"
37 #include "pbd/whitespace.h"
38 #include "pbd/memento_command.h"
39 #include "pbd/enumwriter.h"
40 #include "pbd/stateful_diff_command.h"
42 #include "evoral/Parameter.hpp"
44 #include "ardour/amp.h"
45 #include "ardour/meter.h"
46 #include "ardour/event_type_map.h"
47 #include "ardour/pannable.h"
48 #include "ardour/panner.h"
49 #include "ardour/processor.h"
50 #include "ardour/profile.h"
51 #include "ardour/route_group.h"
52 #include "ardour/session.h"
53 #include "ardour/session_playlists.h"
54 #include "ardour/track.h"
56 #include "canvas/debug.h"
58 #include "gtkmm2ext/gtk_ui.h"
59 #include "gtkmm2ext/utils.h"
61 #include "widgets/ardour_button.h"
62 #include "widgets/prompter.h"
63 #include "widgets/tooltips.h"
65 #include "ardour_ui.h"
66 #include "audio_streamview.h"
68 #include "enums_convert.h"
69 #include "route_time_axis.h"
70 #include "automation_time_axis.h"
72 #include "gui_thread.h"
73 #include "item_counts.h"
75 #include "paste_context.h"
76 #include "playlist_selector.h"
77 #include "point_selection.h"
78 #include "public_editor.h"
79 #include "region_view.h"
80 #include "rgb_macros.h"
81 #include "selection.h"
82 #include "streamview.h"
83 #include "ui_config.h"
85 #include "route_group_menu.h"
89 using namespace ARDOUR;
90 using namespace ArdourWidgets;
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 (Gtkmm2ext::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 ()
1083 using namespace ARDOUR_UI_UTILS;
1085 _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 Prompter 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 Prompter 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 ();
1344 _editor.set_selected_mixer_strip (*this);
1348 RouteTimeAxisView::set_selected_points (PointSelection& points)
1350 StripableTimeAxisView::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 */
1385 StripableTimeAxisView::get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
1389 RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
1392 _view->get_inverted_selectables (sel, results);
1394 StripableTimeAxisView::get_inverted_selectables (sel, results);
1398 RouteTimeAxisView::route_group () const
1400 return _route->route_group();
1403 boost::shared_ptr<Playlist>
1404 RouteTimeAxisView::playlist () const
1406 boost::shared_ptr<Track> tr;
1408 if ((tr = track()) != 0) {
1409 return tr->playlist();
1411 return boost::shared_ptr<Playlist> ();
1416 RouteTimeAxisView::name_entry_changed (string const& str)
1418 if (str == _route->name()) {
1424 strip_whitespace_edges (x);
1430 if (_session->route_name_internal (x)) {
1431 ARDOUR_UI::instance()->popup_error (string_compose (_("The name \"%1\" is reserved for %2"), x, PROGRAM_NAME));
1433 } else if (RouteUI::verify_new_route_name (x)) {
1434 _route->set_name (x);
1441 boost::shared_ptr<Region>
1442 RouteTimeAxisView::find_next_region (framepos_t pos, RegionPoint point, int32_t dir)
1444 boost::shared_ptr<Playlist> pl = playlist ();
1447 return pl->find_next_region (pos, point, dir);
1450 return boost::shared_ptr<Region> ();
1454 RouteTimeAxisView::find_next_region_boundary (framepos_t pos, int32_t dir)
1456 boost::shared_ptr<Playlist> pl = playlist ();
1459 return pl->find_next_region_boundary (pos, dir);
1466 RouteTimeAxisView::fade_range (TimeSelection& selection)
1468 boost::shared_ptr<Playlist> what_we_got;
1469 boost::shared_ptr<Track> tr = track ();
1470 boost::shared_ptr<Playlist> playlist;
1473 /* route is a bus, not a track */
1477 playlist = tr->playlist();
1479 TimeSelection time (selection);
1480 float const speed = tr->speed();
1481 if (speed != 1.0f) {
1482 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1483 (*i).start = session_frame_to_track_frame((*i).start, speed);
1484 (*i).end = session_frame_to_track_frame((*i).end, speed);
1488 playlist->clear_changes ();
1489 playlist->clear_owned_changes ();
1491 playlist->fade_range (time);
1493 vector<Command*> cmds;
1494 playlist->rdiff (cmds);
1495 _session->add_commands (cmds);
1496 _session->add_command (new StatefulDiffCommand (playlist));
1501 RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
1503 boost::shared_ptr<Playlist> what_we_got;
1504 boost::shared_ptr<Track> tr = track ();
1505 boost::shared_ptr<Playlist> playlist;
1508 /* route is a bus, not a track */
1512 playlist = tr->playlist();
1514 TimeSelection time (selection.time);
1515 float const speed = tr->speed();
1516 if (speed != 1.0f) {
1517 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1518 (*i).start = session_frame_to_track_frame((*i).start, speed);
1519 (*i).end = session_frame_to_track_frame((*i).end, speed);
1523 playlist->clear_changes ();
1524 playlist->clear_owned_changes ();
1528 if (playlist->cut (time) != 0) {
1529 if (Config->get_edit_mode() == Ripple) {
1530 playlist->ripple(time.start(), -time.length(), NULL);
1532 // no need to exclude any regions from rippling here
1534 vector<Command*> cmds;
1535 playlist->rdiff (cmds);
1536 _session->add_commands (cmds);
1538 _session->add_command (new StatefulDiffCommand (playlist));
1543 if ((what_we_got = playlist->cut (time)) != 0) {
1544 _editor.get_cut_buffer().add (what_we_got);
1545 if (Config->get_edit_mode() == Ripple) {
1546 playlist->ripple(time.start(), -time.length(), NULL);
1548 // no need to exclude any regions from rippling here
1550 vector<Command*> cmds;
1551 playlist->rdiff (cmds);
1552 _session->add_commands (cmds);
1554 _session->add_command (new StatefulDiffCommand (playlist));
1558 if ((what_we_got = playlist->copy (time)) != 0) {
1559 _editor.get_cut_buffer().add (what_we_got);
1564 if ((what_we_got = playlist->cut (time)) != 0) {
1565 if (Config->get_edit_mode() == Ripple) {
1566 playlist->ripple(time.start(), -time.length(), NULL);
1568 // no need to exclude any regions from rippling here
1570 vector<Command*> cmds;
1571 playlist->rdiff (cmds);
1572 _session->add_commands (cmds);
1573 _session->add_command (new StatefulDiffCommand (playlist));
1574 what_we_got->release ();
1581 RouteTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1587 boost::shared_ptr<Playlist> pl = playlist ();
1588 const ARDOUR::DataType type = pl->data_type();
1589 PlaylistSelection::const_iterator p = selection.playlists.get_nth(type, ctx.counts.n_playlists(type));
1591 if (p == selection.playlists.end()) {
1594 ctx.counts.increase_n_playlists(type);
1596 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("paste to %1\n", pos));
1598 if (track()->speed() != 1.0f) {
1599 pos = session_frame_to_track_frame (pos, track()->speed());
1600 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("modified paste to %1\n", pos));
1603 /* add multi-paste offset if applicable */
1604 std::pair<framepos_t, framepos_t> extent = (*p)->get_extent();
1605 const framecnt_t duration = extent.second - extent.first;
1606 pos += _editor.get_paste_offset(pos, ctx.count, duration);
1608 pl->clear_changes ();
1609 pl->clear_owned_changes ();
1610 if (Config->get_edit_mode() == Ripple) {
1611 std::pair<framepos_t, framepos_t> extent = (*p)->get_extent_with_endspace();
1612 framecnt_t amount = extent.second - extent.first;
1613 pl->ripple(pos, amount * ctx.times, boost::shared_ptr<Region>());
1615 pl->paste (*p, pos, ctx.times, sub_num);
1617 vector<Command*> cmds;
1619 _session->add_commands (cmds);
1621 _session->add_command (new StatefulDiffCommand (pl));
1627 struct PlaylistSorter {
1628 bool operator() (boost::shared_ptr<Playlist> a, boost::shared_ptr<Playlist> b) const {
1629 return a->sort_id() < b->sort_id();
1634 RouteTimeAxisView::build_playlist_menu ()
1636 using namespace Menu_Helpers;
1642 delete playlist_action_menu;
1643 playlist_action_menu = new Menu;
1644 playlist_action_menu->set_name ("ArdourContextMenu");
1646 MenuList& playlist_items = playlist_action_menu->items();
1647 playlist_action_menu->set_name ("ArdourContextMenu");
1648 playlist_items.clear();
1650 RadioMenuItem::Group playlist_group;
1651 boost::shared_ptr<Track> tr = track ();
1653 vector<boost::shared_ptr<Playlist> > playlists_tr = _session->playlists->playlists_for_track (tr);
1655 /* sort the playlists */
1657 sort (playlists_tr.begin(), playlists_tr.end(), cmp);
1659 /* add the playlists to the menu */
1660 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) {
1661 playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name()));
1662 RadioMenuItem *item = static_cast<RadioMenuItem*>(&playlist_items.back());
1663 item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist), item, boost::weak_ptr<Playlist> (*i)));
1665 if (tr->playlist()->id() == (*i)->id()) {
1670 playlist_items.push_back (SeparatorElem());
1671 playlist_items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
1672 playlist_items.push_back (SeparatorElem());
1674 if (!route_group() || !route_group()->is_active() || !route_group()->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1675 playlist_items.push_back (MenuElem (_("New..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1676 playlist_items.push_back (MenuElem (_("New Copy..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1679 // Use a label which tells the user what is happening
1680 playlist_items.push_back (MenuElem (_("New Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1681 playlist_items.push_back (MenuElem (_("Copy Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1685 playlist_items.push_back (SeparatorElem());
1686 playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::clear_playlists), this)));
1687 playlist_items.push_back (SeparatorElem());
1689 playlist_items.push_back (MenuElem(_("Select from All..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
1693 RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist> wpl)
1695 assert (is_track());
1697 // exit if we were triggered by deactivating the old playlist
1698 if (!item->get_active()) {
1702 boost::shared_ptr<Playlist> pl (wpl.lock());
1708 if (track()->playlist() == pl) {
1709 // exit when use_playlist is called by the creation of the playlist menu
1710 // or the playlist choice is unchanged
1714 track()->use_playlist (pl);
1716 RouteGroup* rg = route_group();
1718 if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1719 std::string group_string = "." + rg->name() + ".";
1721 std::string take_name = pl->name();
1722 std::string::size_type idx = take_name.find(group_string);
1724 if (idx == std::string::npos)
1727 take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
1729 boost::shared_ptr<RouteList> rl (rg->route_list());
1731 for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
1732 if ((*i) == this->route()) {
1736 std::string playlist_name = (*i)->name()+group_string+take_name;
1738 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
1743 if (track->freeze_state() == Track::Frozen) {
1744 /* Don't change playlists of frozen tracks */
1748 boost::shared_ptr<Playlist> ipl = session()->playlists->by_name(playlist_name);
1750 // No playlist for this track for this take yet, make it
1751 track->use_new_playlist();
1752 track->playlist()->set_name(playlist_name);
1754 track->use_playlist(ipl);
1761 RouteTimeAxisView::update_playlist_tip ()
1763 RouteGroup* rg = route_group ();
1764 if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1765 string group_string = "." + rg->name() + ".";
1767 string take_name = track()->playlist()->name();
1768 string::size_type idx = take_name.find(group_string);
1770 if (idx != string::npos) {
1771 /* find the bit containing the take number / name */
1772 take_name = take_name.substr (idx + group_string.length());
1774 /* set the playlist button tooltip to the take name */
1777 string_compose(_("Take: %1.%2"),
1778 Gtkmm2ext::markup_escape_text (rg->name()),
1779 Gtkmm2ext::markup_escape_text (take_name))
1786 /* set the playlist button tooltip to the playlist name */
1787 set_tooltip (playlist_button, _("Playlist") + std::string(": ") + Gtkmm2ext::markup_escape_text (track()->playlist()->name()));
1792 RouteTimeAxisView::show_playlist_selector ()
1794 _editor.playlist_selector().show_for (this);
1798 RouteTimeAxisView::map_frozen ()
1804 ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::map_frozen)
1806 switch (track()->freeze_state()) {
1808 playlist_button.set_sensitive (false);
1811 playlist_button.set_sensitive (true);
1814 RouteUI::map_frozen ();
1818 RouteTimeAxisView::color_handler ()
1820 //case cTimeStretchOutline:
1821 if (timestretch_rect) {
1822 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
1824 //case cTimeStretchFill:
1825 if (timestretch_rect) {
1826 timestretch_rect->set_fill_color (UIConfiguration::instance().color ("time stretch fill"));
1832 /** Toggle an automation track for a fully-specified Parameter (type,channel,id)
1833 * Will add track if necessary.
1836 RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
1838 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1839 Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1842 /* it doesn't exist yet, so we don't care about the button state: just add it */
1843 create_automation_child (param, true);
1846 bool yn = menu->get_active();
1847 bool changed = false;
1849 if ((changed = track->set_marked_for_display (menu->get_active())) && yn) {
1851 /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
1852 will have done that for us.
1855 if (changed && !no_redraw) {
1863 RouteTimeAxisView::update_pan_track_visibility ()
1865 bool const showit = pan_automation_item->get_active();
1866 bool changed = false;
1868 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1869 if ((*i)->set_marked_for_display (showit)) {
1875 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1880 RouteTimeAxisView::ensure_pan_views (bool show)
1882 bool changed = false;
1883 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1885 (*i)->set_marked_for_display (false);
1888 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1892 if (!_route->panner()) {
1896 set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1897 set<Evoral::Parameter>::iterator p;
1899 for (p = params.begin(); p != params.end(); ++p) {
1900 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1902 if (pan_control->parameter().type() == NullAutomation) {
1903 error << "Pan control has NULL automation type!" << endmsg;
1907 if (automation_child (pan_control->parameter ()).get () == 0) {
1909 /* we don't already have an AutomationTimeAxisView for this parameter */
1911 std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
1913 boost::shared_ptr<AutomationTimeAxisView> t (
1914 new AutomationTimeAxisView (_session,
1918 pan_control->parameter (),
1926 pan_tracks.push_back (t);
1927 add_automation_child (*p, t, show);
1929 pan_tracks.push_back (automation_child (pan_control->parameter ()));
1936 RouteTimeAxisView::show_all_automation (bool apply_to_selection)
1938 if (apply_to_selection) {
1939 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_all_automation, _1, false));
1943 StripableTimeAxisView::show_all_automation ();
1945 /* Show processor automation */
1947 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1948 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1949 if ((*ii)->view == 0) {
1950 add_processor_automation_curve ((*i)->processor, (*ii)->what);
1953 (*ii)->menu_item->set_active (true);
1966 RouteTimeAxisView::show_existing_automation (bool apply_to_selection)
1968 if (apply_to_selection) {
1969 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_existing_automation, _1, false));
1973 StripableTimeAxisView::show_existing_automation ();
1975 /* Show processor automation */
1976 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1977 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1978 if ((*i)->processor->control((*ii)->what)->list()->size() > 0) {
1979 (*ii)->menu_item->set_active (true);
1990 RouteTimeAxisView::hide_all_automation (bool apply_to_selection)
1992 if (apply_to_selection) {
1993 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::hide_all_automation, _1, false));
1996 StripableTimeAxisView::hide_all_automation ();
1998 /* Hide processor automation */
1999 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2000 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2001 (*ii)->menu_item->set_active (false);
2011 RouteTimeAxisView::region_view_added (RegionView* rv)
2013 /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
2014 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
2015 boost::shared_ptr<AutomationTimeAxisView> atv;
2017 if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
2022 for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
2023 (*i)->add_ghost(rv);
2027 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
2029 for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
2035 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
2037 parent.remove_processor_automation_node (this);
2041 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
2044 remove_child (pan->view);
2048 RouteTimeAxisView::ProcessorAutomationNode*
2049 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2051 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2053 if ((*i)->processor == processor) {
2055 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2056 if ((*ii)->what == what) {
2066 /** Add an AutomationTimeAxisView to display automation for a processor's parameter */
2068 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2071 ProcessorAutomationNode* pan;
2073 if ((pan = find_processor_automation_node (processor, what)) == 0) {
2074 /* session state may never have been saved with new plugin */
2075 error << _("programming error: ")
2076 << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"),
2077 processor->name(), what.type(), (int) what.channel(), what.id() )
2079 abort(); /*NOTREACHED*/
2087 boost::shared_ptr<AutomationControl> control
2088 = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
2090 pan->view = boost::shared_ptr<AutomationTimeAxisView>(
2091 new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (),
2092 _editor, *this, false, parent_canvas,
2093 processor->describe_parameter (what), processor->name()));
2095 pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
2097 add_automation_child (control->parameter(), pan->view, pan->view->marked_for_display ());
2100 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
2105 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor>)
2108 pan->menu_item->set_active (false);
2117 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
2119 boost::shared_ptr<Processor> processor (p.lock ());
2121 if (!processor || boost::dynamic_pointer_cast<Amp> (processor)) {
2122 /* The Amp processor is a special case and is dealt with separately */
2126 set<Evoral::Parameter> existing;
2128 processor->what_has_data (existing);
2130 for (set<Evoral::Parameter>::iterator i = existing.begin(); i != existing.end(); ++i) {
2132 Evoral::Parameter param (*i);
2133 boost::shared_ptr<AutomationLine> al;
2135 if ((al = find_processor_automation_curve (processor, param)) != 0) {
2138 add_processor_automation_curve (processor, param);
2144 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
2146 boost::shared_ptr<Processor> processor (p.lock ());
2148 if (!processor || !processor->display_to_user ()) {
2152 /* we use this override to veto the Amp processor from the plugin menu,
2153 as its automation lane can be accessed using the special "Fader" menu
2157 if (boost::dynamic_pointer_cast<Amp> (processor) != 0) {
2161 using namespace Menu_Helpers;
2162 ProcessorAutomationInfo *rai;
2163 list<ProcessorAutomationInfo*>::iterator x;
2165 const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
2167 if (automatable.empty()) {
2171 for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
2172 if ((*x)->processor == processor) {
2177 if (x == processor_automation.end()) {
2178 rai = new ProcessorAutomationInfo (processor);
2179 processor_automation.push_back (rai);
2184 /* any older menu was deleted at the top of processors_changed()
2185 when we cleared the subplugin menu.
2188 rai->menu = manage (new Menu);
2189 MenuList& items = rai->menu->items();
2190 rai->menu->set_name ("ArdourContextMenu");
2194 std::set<Evoral::Parameter> has_visible_automation;
2195 AutomationTimeAxisView::what_has_visible_automation (processor, has_visible_automation);
2197 for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2199 ProcessorAutomationNode* pan;
2200 Gtk::CheckMenuItem* mitem;
2202 string name = processor->describe_parameter (*i);
2204 if (name == X_("hidden")) {
2208 items.push_back (CheckMenuElem (name));
2209 mitem = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
2211 _subplugin_menu_map[*i] = mitem;
2213 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2214 mitem->set_active(true);
2217 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2221 pan = new ProcessorAutomationNode (*i, mitem, *this);
2223 rai->lines.push_back (pan);
2227 pan->menu_item = mitem;
2231 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2234 if (items.size() == 0) {
2238 /* add the menu for this processor, because the subplugin
2239 menu is always cleared at the top of processors_changed().
2240 this is the result of some poor design in gtkmm and/or
2244 subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2249 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2250 RouteTimeAxisView::ProcessorAutomationNode* pan)
2252 bool showit = pan->menu_item->get_active();
2253 bool redraw = false;
2255 if (pan->view == 0 && showit) {
2256 add_processor_automation_curve (rai->processor, pan->what);
2260 if (pan->view && pan->view->set_marked_for_display (showit)) {
2264 if (redraw && !no_redraw) {
2270 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2272 if (c.type == RouteProcessorChange::MeterPointChange) {
2273 /* nothing to do if only the meter point has changed */
2277 using namespace Menu_Helpers;
2279 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2280 (*i)->valid = false;
2283 setup_processor_menu_and_curves ();
2285 bool deleted_processor_automation = false;
2287 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2289 list<ProcessorAutomationInfo*>::iterator tmp;
2297 processor_automation.erase (i);
2298 deleted_processor_automation = true;
2305 if (deleted_processor_automation && !no_redraw) {
2310 boost::shared_ptr<AutomationLine>
2311 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2313 ProcessorAutomationNode* pan;
2315 if ((pan = find_processor_automation_node (processor, what)) != 0) {
2321 return boost::shared_ptr<AutomationLine>();
2325 RouteTimeAxisView::reset_processor_automation_curves ()
2327 for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2333 RouteTimeAxisView::can_edit_name () const
2335 /* we do not allow track name changes if it is record enabled
2337 boost::shared_ptr<Track> trk (boost::dynamic_pointer_cast<Track> (_route));
2341 return !trk->rec_enable_control()->get_value();
2345 RouteTimeAxisView::blink_rec_display (bool onoff)
2347 RouteUI::blink_rec_display (onoff);
2351 RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection)
2353 if (_ignore_set_layer_display) {
2357 if (apply_to_selection) {
2358 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false));
2362 _view->set_layer_display (d);
2365 set_gui_property (X_("layer-display"), d);
2370 RouteTimeAxisView::layer_display () const
2373 return _view->layer_display ();
2376 /* we don't know, since we don't have a _view, so just return something */
2381 RouteTimeAxisView::fast_update ()
2383 gm.get_level_meter().update_meters ();
2387 RouteTimeAxisView::hide_meter ()
2390 gm.get_level_meter().hide_meters ();
2394 RouteTimeAxisView::show_meter ()
2400 RouteTimeAxisView::reset_meter ()
2402 if (UIConfiguration::instance().get_show_track_meters()) {
2403 int meter_width = 3;
2404 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
2407 gm.get_level_meter().setup_meters (height - 9, meter_width);
2414 RouteTimeAxisView::clear_meter ()
2416 gm.get_level_meter().clear_meters ();
2420 RouteTimeAxisView::meter_changed ()
2422 ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed)
2424 if (_route && !no_redraw && UIConfiguration::instance().get_show_track_meters()) {
2427 // reset peak when meter point changes
2428 gm.reset_peak_display();
2432 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2435 if (_route && !no_redraw) {
2441 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu)
2443 using namespace Menu_Helpers;
2445 if (!_underlay_streams.empty()) {
2446 MenuList& parent_items = parent_menu->items();
2447 Menu* gs_menu = manage (new Menu);
2448 gs_menu->set_name ("ArdourContextMenu");
2449 MenuList& gs_items = gs_menu->items();
2451 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2453 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2454 gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2455 sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2461 RouteTimeAxisView::set_underlay_state()
2463 if (!underlay_xml_node) {
2467 XMLNodeList nlist = underlay_xml_node->children();
2468 XMLNodeConstIterator niter;
2469 XMLNode *child_node;
2471 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2472 child_node = *niter;
2474 if (child_node->name() != "Underlay") {
2478 XMLProperty const * prop = child_node->property ("id");
2480 PBD::ID id (prop->value());
2482 StripableTimeAxisView* v = _editor.get_stripable_time_axis_by_id (id);
2485 add_underlay(v->view(), false);
2494 RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/)
2500 RouteTimeAxisView& other = v->trackview();
2502 if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2503 if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2504 fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2505 abort(); /*NOTREACHED*/
2508 _underlay_streams.push_back(v);
2509 other._underlay_mirrors.push_back(this);
2511 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2513 #ifdef GUI_OBJECT_STATE_FIX_REQUIRED
2515 if (!underlay_xml_node) {
2516 underlay_xml_node = xml_node->add_child("Underlays");
2519 XMLNode* node = underlay_xml_node->add_child("Underlay");
2520 XMLProperty const * prop = node->add_property("id");
2521 prop->set_value(v->trackview().route()->id().to_s());
2528 RouteTimeAxisView::remove_underlay (StreamView* v)
2534 UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2535 RouteTimeAxisView& other = v->trackview();
2537 if (it != _underlay_streams.end()) {
2538 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2540 if (gm == other._underlay_mirrors.end()) {
2541 fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2542 abort(); /*NOTREACHED*/
2545 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2547 _underlay_streams.erase(it);
2548 other._underlay_mirrors.erase(gm);
2550 if (underlay_xml_node) {
2551 underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2557 RouteTimeAxisView::set_button_names ()
2559 if (_route && _route->solo_safe_control()->solo_safe()) {
2560 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2562 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2564 if (Config->get_solo_control_is_listen_control()) {
2565 switch (Config->get_listen_position()) {
2566 case AfterFaderListen:
2567 solo_button->set_text (S_("AfterFader|A"));
2568 set_tooltip (*solo_button, _("After-fade listen (AFL)"));
2570 case PreFaderListen:
2571 solo_button->set_text (S_("PreFader|P"));
2572 set_tooltip (*solo_button, _("Pre-fade listen (PFL)"));
2576 solo_button->set_text (S_("Solo|S"));
2577 set_tooltip (*solo_button, _("Solo"));
2579 mute_button->set_text (S_("Mute|M"));
2583 RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
2585 Gtk::CheckMenuItem* rv = StripableTimeAxisView::automation_child_menu_item (param);
2590 ParameterMenuMap::iterator i = _subplugin_menu_map.find (param);
2591 if (i != _subplugin_menu_map.end()) {
2599 RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, bool show)
2601 boost::shared_ptr<AutomationControl> c = _route->gain_control();
2603 error << "Route has no gain automation, unable to add automation track view." << endmsg;
2607 gain_track.reset (new AutomationTimeAxisView (_session,
2608 _route, _route->amp(), c, param,
2613 _route->amp()->describe_parameter(param)));
2616 _view->foreach_regionview (sigc::mem_fun (*gain_track.get(), &TimeAxisView::add_ghost));
2619 add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
2623 RouteTimeAxisView::create_trim_automation_child (const Evoral::Parameter& param, bool show)
2625 boost::shared_ptr<AutomationControl> c = _route->trim()->gain_control();
2626 if (!c || ! _route->trim()->active()) {
2630 trim_track.reset (new AutomationTimeAxisView (_session,
2631 _route, _route->trim(), c, param,
2636 _route->trim()->describe_parameter(param)));
2639 _view->foreach_regionview (sigc::mem_fun (*trim_track.get(), &TimeAxisView::add_ghost));
2642 add_automation_child (Evoral::Parameter(TrimAutomation), trim_track, show);
2646 RouteTimeAxisView::create_mute_automation_child (const Evoral::Parameter& param, bool show)
2648 boost::shared_ptr<AutomationControl> c = _route->mute_control();
2650 error << "Route has no mute automation, unable to add automation track view." << endmsg;
2654 mute_track.reset (new AutomationTimeAxisView (_session,
2655 _route, _route, c, param,
2660 _route->describe_parameter(param)));
2663 _view->foreach_regionview (sigc::mem_fun (*mute_track.get(), &TimeAxisView::add_ghost));
2666 add_automation_child (Evoral::Parameter(MuteAutomation), mute_track, show);
2670 void add_region_to_list (RegionView* rv, RegionList* l)
2672 l->push_back (rv->region());
2676 RouteTimeAxisView::combine_regions ()
2678 /* as of may 2011, we do not offer uncombine for MIDI tracks
2681 if (!is_audio_track()) {
2689 RegionList selected_regions;
2690 boost::shared_ptr<Playlist> playlist = track()->playlist();
2692 _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2694 if (selected_regions.size() < 2) {
2698 playlist->clear_changes ();
2699 boost::shared_ptr<Region> compound_region = playlist->combine (selected_regions);
2701 _session->add_command (new StatefulDiffCommand (playlist));
2702 /* make the new region be selected */
2704 return _view->find_view (compound_region);
2708 RouteTimeAxisView::uncombine_regions ()
2710 /* as of may 2011, we do not offer uncombine for MIDI tracks
2712 if (!is_audio_track()) {
2720 RegionList selected_regions;
2721 boost::shared_ptr<Playlist> playlist = track()->playlist();
2723 /* have to grab selected regions first because the uncombine is going
2724 * to change that in the middle of the list traverse
2727 _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2729 playlist->clear_changes ();
2731 for (RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) {
2732 playlist->uncombine (*i);
2735 _session->add_command (new StatefulDiffCommand (playlist));
2739 RouteTimeAxisView::state_id() const
2741 return string_compose ("rtav %1", _route->id().to_s());
2746 RouteTimeAxisView::remove_child (boost::shared_ptr<TimeAxisView> c)
2748 TimeAxisView::remove_child (c);
2750 boost::shared_ptr<AutomationTimeAxisView> a = boost::dynamic_pointer_cast<AutomationTimeAxisView> (c);
2752 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2753 if (i->second == a) {
2754 _automation_tracks.erase (i);
2762 RouteTimeAxisView::color () const
2764 return route_color ();
2768 RouteTimeAxisView::marked_for_display () const
2770 return !_route->presentation_info().hidden();
2774 RouteTimeAxisView::set_marked_for_display (bool yn)
2776 return RouteUI::mark_hidden (!yn);