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 "route_time_axis.h"
65 #include "automation_time_axis.h"
67 #include "gui_thread.h"
68 #include "item_counts.h"
70 #include "paste_context.h"
71 #include "playlist_selector.h"
72 #include "point_selection.h"
74 #include "public_editor.h"
75 #include "region_view.h"
76 #include "rgb_macros.h"
77 #include "selection.h"
78 #include "streamview.h"
80 #include "ui_config.h"
82 #include "route_group_menu.h"
84 #include "ardour/track.h"
88 using namespace ARDOUR;
89 using namespace ARDOUR_UI_UTILS;
91 using namespace Gtkmm2ext;
93 using namespace Editing;
97 RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
99 , TimeAxisView(sess,ed,(TimeAxisView*) 0, canvas)
101 , parent_canvas (canvas)
103 , button_table (3, 3)
104 , route_group_button (S_("RTAV|G"))
105 , playlist_button (S_("RTAV|P"))
106 , automation_button (S_("RTAV|A"))
107 , automation_action_menu (0)
108 , plugins_submenu_item (0)
109 , route_group_menu (0)
110 , playlist_action_menu (0)
112 , color_mode_menu (0)
113 , gm (sess, true, 75, 14)
114 , _ignore_set_layer_display (false)
115 , gain_automation_item(NULL)
116 , trim_automation_item(NULL)
117 , mute_automation_item(NULL)
118 , pan_automation_item(NULL)
120 number_label.set_name("tracknumber label");
121 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
122 number_label.set_alignment(.5, .5);
123 number_label.set_fallthrough_to_parent (true);
125 sess->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::parameter_changed, this, _1), gui_context());
126 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::parameter_changed));
128 parameter_changed ("editor-stereo-only-meters");
132 RouteTimeAxisView::route_property_changed (const PBD::PropertyChange& what_changed)
134 if (what_changed.contains (ARDOUR::Properties::name)) {
140 RouteTimeAxisView::set_route (boost::shared_ptr<Route> rt)
142 RouteUI::set_route (rt);
144 CANVAS_DEBUG_NAME (_canvas_display, string_compose ("main for %1", rt->name()));
145 CANVAS_DEBUG_NAME (selection_group, string_compose ("selections for %1", rt->name()));
146 CANVAS_DEBUG_NAME (_ghost_group, string_compose ("ghosts for %1", rt->name()));
149 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
152 gm.set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
153 gm.get_level_meter().set_no_show_all();
154 gm.get_level_meter().setup_meters(50, meter_width);
155 gm.update_gain_sensitive ();
157 string str = gui_property ("height");
159 set_height (atoi (str));
161 set_height (preset_height (HeightNormal));
164 if (!_route->is_auditioner()) {
165 if (gui_property ("visible").empty()) {
166 set_gui_property ("visible", true);
169 set_gui_property ("visible", false);
172 timestretch_rect = 0;
175 ignore_toggle = false;
177 route_group_button.set_name ("route button");
178 playlist_button.set_name ("route button");
179 automation_button.set_name ("route button");
181 route_group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::route_group_click), false);
182 playlist_button.signal_button_press_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::playlist_click), false);
183 automation_button.signal_button_press_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::automation_click), false);
187 if (ARDOUR::Profile->get_mixbus()) {
188 controls_table.attach (*rec_enable_button, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
190 controls_table.attach (*rec_enable_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
193 if (is_midi_track()) {
194 set_tooltip(*rec_enable_button, _("Record (Right-click for Step Edit)"));
195 gm.set_fader_name ("MidiTrackFader");
197 set_tooltip(*rec_enable_button, _("Record"));
198 gm.set_fader_name ("AudioTrackFader");
201 /* set playlist button tip to the current playlist, and make it update when it changes */
202 update_playlist_tip ();
203 track()->PlaylistChanged.connect (*this, invalidator (*this), ui_bind(&RouteTimeAxisView::update_playlist_tip, this), gui_context());
206 gm.set_fader_name ("AudioBusFader");
207 Gtk::Fixed *blank = manage(new Gtk::Fixed());
208 controls_button_size_group->add_widget(*blank);
209 if (ARDOUR::Profile->get_mixbus() ) {
210 controls_table.attach (*blank, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
212 controls_table.attach (*blank, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
217 top_hbox.pack_end(gm.get_level_meter(), false, false, 2);
219 if (!ARDOUR::Profile->get_mixbus()) {
220 controls_meters_size_group->add_widget (gm.get_level_meter());
223 _route->meter_change.connect (*this, invalidator (*this), bind (&RouteTimeAxisView::meter_changed, this), gui_context());
224 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
225 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
226 _route->track_number_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::label_view, this), gui_context());
228 if (ARDOUR::Profile->get_mixbus()) {
229 controls_table.attach (*mute_button, 1, 2, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
231 controls_table.attach (*mute_button, 3, 4, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
233 // mute button is always present, it is used to
234 // force the 'blank' placeholders to the proper size
235 controls_button_size_group->add_widget(*mute_button);
237 if (!_route->is_master()) {
238 if (ARDOUR::Profile->get_mixbus()) {
239 controls_table.attach (*solo_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
241 controls_table.attach (*solo_button, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
244 Gtk::Fixed *blank = manage(new Gtk::Fixed());
245 controls_button_size_group->add_widget(*blank);
246 if (ARDOUR::Profile->get_mixbus()) {
247 controls_table.attach (*blank, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
249 controls_table.attach (*blank, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
254 if (ARDOUR::Profile->get_mixbus()) {
255 controls_table.attach (route_group_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
256 controls_table.attach (gm.get_gain_slider(), 3, 5, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0);
258 else if (!ARDOUR::Profile->get_trx()) {
259 controls_table.attach (route_group_button, 4, 5, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
260 controls_table.attach (gm.get_gain_slider(), 0, 2, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0);
263 set_tooltip(*solo_button,_("Solo"));
264 set_tooltip(*mute_button,_("Mute"));
265 set_tooltip(route_group_button, _("Route Group"));
267 mute_button->set_tweaks(ArdourButton::TrackHeader);
268 solo_button->set_tweaks(ArdourButton::TrackHeader);
269 rec_enable_button->set_tweaks(ArdourButton::TrackHeader);
270 playlist_button.set_tweaks(ArdourButton::TrackHeader);
271 automation_button.set_tweaks(ArdourButton::TrackHeader);
272 route_group_button.set_tweaks(ArdourButton::TrackHeader);
274 if (is_midi_track()) {
275 set_tooltip(automation_button, _("MIDI Controllers and Automation"));
277 set_tooltip(automation_button, _("Automation"));
280 update_track_number_visibility();
283 if (ARDOUR::Profile->get_mixbus()) {
284 controls_table.attach (automation_button, 1, 2, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
286 else if (!ARDOUR::Profile->get_trx()) {
287 controls_table.attach (automation_button, 3, 4, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
290 if (is_track() && track()->mode() == ARDOUR::Normal) {
291 if (ARDOUR::Profile->get_mixbus()) {
292 controls_table.attach (playlist_button, 0, 1, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
294 else if (!ARDOUR::Profile->get_trx()) {
295 controls_table.attach (playlist_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
301 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::processors_changed, this, _1), gui_context());
305 str = gui_property ("layer-display");
307 set_layer_display (LayerDisplay (string_2_enum (str, _view->layer_display ())));
310 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::map_frozen, this), gui_context());
311 track()->SpeedChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::speed_changed, this), gui_context());
313 /* pick up the correct freeze state */
318 _editor.ZoomChanged.connect (sigc::mem_fun(*this, &RouteTimeAxisView::reset_samples_per_pixel));
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 ()), std::dec));
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 if (!subplugin_menu.items().empty()) {
542 items.push_back (SeparatorElem ());
543 items.push_back (MenuElem (_("Processor automation"), subplugin_menu));
544 items.back().set_sensitive (!for_selection || _editor.get_selection().tracks.size() == 1);;
547 /* Add any route automation */
550 items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &RouteTimeAxisView::update_gain_track_visibility)));
551 gain_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
552 gain_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
553 (gain_track && string_is_affirmative (gain_track->gui_property ("visible"))));
555 _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
559 items.push_back (CheckMenuElem (_("Trim"), sigc::mem_fun (*this, &RouteTimeAxisView::update_trim_track_visibility)));
560 trim_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
561 trim_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
562 (trim_track && string_is_affirmative (trim_track->gui_property ("visible"))));
564 _main_automation_menu_map[Evoral::Parameter(TrimAutomation)] = trim_automation_item;
568 items.push_back (CheckMenuElem (_("Mute"), sigc::mem_fun (*this, &RouteTimeAxisView::update_mute_track_visibility)));
569 mute_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
570 mute_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
571 (mute_track && string_is_affirmative (mute_track->gui_property ("visible"))));
573 _main_automation_menu_map[Evoral::Parameter(MuteAutomation)] = mute_automation_item;
576 if (!pan_tracks.empty()) {
577 items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &RouteTimeAxisView::update_pan_track_visibility)));
578 pan_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
579 pan_automation_item->set_active ((!for_selection || _editor.get_selection().tracks.size() == 1) &&
580 (!pan_tracks.empty() && string_is_affirmative (pan_tracks.front()->gui_property ("visible"))));
582 set<Evoral::Parameter> const & params = _route->pannable()->what_can_be_automated ();
583 for (set<Evoral::Parameter>::const_iterator p = params.begin(); p != params.end(); ++p) {
584 _main_automation_menu_map[*p] = pan_automation_item;
590 RouteTimeAxisView::build_display_menu ()
592 using namespace Menu_Helpers;
596 TimeAxisView::build_display_menu ();
598 /* now fill it with our stuff */
600 MenuList& items = display_menu->items();
601 display_menu->set_name ("ArdourContextMenu");
603 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
605 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
607 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
609 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
611 items.push_back (SeparatorElem());
614 detach_menu (*_size_menu);
617 items.push_back (MenuElem (_("Height"), *_size_menu));
618 items.push_back (SeparatorElem());
620 // Hook for derived classes to add type specific stuff
621 append_extra_display_menu_items ();
625 Menu* layers_menu = manage (new Menu);
626 MenuList &layers_items = layers_menu->items();
627 layers_menu->set_name("ArdourContextMenu");
629 RadioMenuItem::Group layers_group;
631 /* Find out how many overlaid/stacked tracks we have in the selection */
635 TrackSelection const & s = _editor.get_selection().tracks;
636 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
637 StreamView* v = (*i)->view ();
642 switch (v->layer_display ()) {
653 /* We're not connecting to signal_toggled() here; in the case where these two items are
654 set to be in the `inconsistent' state, it seems that one or other will end up active
655 as well as inconsistent (presumably due to the RadioMenuItem::Group). Then when you
656 select the active one, no toggled signal is emitted so nothing happens.
659 _ignore_set_layer_display = true;
661 layers_items.push_back (RadioMenuElem (layers_group, _("Overlaid")));
662 RadioMenuItem* i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
663 i->set_active (overlaid != 0 && stacked == 0);
664 i->set_inconsistent (overlaid != 0 && stacked != 0);
665 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Overlaid, true));
667 layers_items.push_back (RadioMenuElem (layers_group, _("Stacked")));
668 i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
669 i->set_active (overlaid == 0 && stacked != 0);
670 i->set_inconsistent (overlaid != 0 && stacked != 0);
671 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true));
673 _ignore_set_layer_display = false;
675 items.push_back (MenuElem (_("Layers"), *layers_menu));
677 Menu* alignment_menu = manage (new Menu);
678 MenuList& alignment_items = alignment_menu->items();
679 alignment_menu->set_name ("ArdourContextMenu");
681 RadioMenuItem::Group align_group;
683 /* Same verbose hacks as for the layering options above */
689 boost::shared_ptr<Track> first_track;
691 for (TrackSelection::const_iterator t = s.begin(); t != s.end(); ++t) {
692 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*t);
693 if (!r || !r->is_track ()) {
698 first_track = r->track();
701 switch (r->track()->alignment_choice()) {
705 switch (r->track()->alignment_style()) {
706 case ExistingMaterial:
714 case UseExistingMaterial:
730 inconsistent = false;
737 if (!inconsistent && first_track) {
739 alignment_items.push_back (RadioMenuElem (align_group, _("Automatic (based on I/O connections)")));
740 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
741 i->set_active (automatic != 0 && existing == 0 && capture == 0);
742 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, Automatic, true));
744 switch (first_track->alignment_choice()) {
746 switch (first_track->alignment_style()) {
747 case ExistingMaterial:
748 alignment_items.push_back (MenuElem (_("(Currently: Existing Material)")));
751 alignment_items.push_back (MenuElem (_("(Currently: Capture Time)")));
759 alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material")));
760 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
761 i->set_active (existing != 0 && capture == 0 && automatic == 0);
762 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseExistingMaterial, true));
764 alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time")));
765 i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
766 i->set_active (existing == 0 && capture != 0 && automatic == 0);
767 i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseCaptureTime, true));
769 items.push_back (MenuElem (_("Alignment"), *alignment_menu));
775 Menu* mode_menu = manage (new Menu);
776 MenuList& mode_items = mode_menu->items ();
777 mode_menu->set_name ("ArdourContextMenu");
779 RadioMenuItem::Group mode_group;
785 for (TrackSelection::const_iterator t = s.begin(); t != s.end(); ++t) {
786 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*t);
787 if (!r || !r->is_track ()) {
791 switch (r->track()->mode()) {
804 mode_items.push_back (RadioMenuElem (mode_group, _("Normal Mode")));
805 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
806 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Normal, true));
807 i->set_active (normal != 0 && tape == 0 && non_layered == 0);
808 i->set_inconsistent (normal != 0 && (tape != 0 || non_layered != 0));
810 mode_items.push_back (RadioMenuElem (mode_group, _("Tape Mode")));
811 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
812 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Destructive, true));
813 i->set_active (normal == 0 && tape != 0 && non_layered == 0);
814 i->set_inconsistent (tape != 0 && (normal != 0 || non_layered != 0));
816 mode_items.push_back (RadioMenuElem (mode_group, _("Non-Layered Mode")));
817 i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
818 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::NonLayered, true));
819 i->set_active (normal == 0 && tape == 0 && non_layered != 0);
820 i->set_inconsistent (non_layered != 0 && (normal != 0 || tape != 0));
822 items.push_back (MenuElem (_("Record Mode"), *mode_menu));
824 items.push_back (SeparatorElem());
826 build_playlist_menu ();
827 items.push_back (MenuElem (_("Playlist"), *playlist_action_menu));
828 items.back().set_sensitive (_editor.get_selection().tracks.size() <= 1);
831 route_group_menu->detach ();
834 for (TrackSelection::iterator i = _editor.get_selection().tracks.begin(); i != _editor.get_selection().tracks.end(); ++i) {
835 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
837 r.push_back (rtv->route ());
842 r.push_back (route ());
845 route_group_menu->build (r);
846 items.push_back (MenuElem (_("Group"), *route_group_menu->menu ()));
848 build_automation_action_menu (true);
849 items.push_back (MenuElem (_("Automation"), *automation_action_menu));
851 items.push_back (SeparatorElem());
855 TrackSelection const & s = _editor.get_selection().tracks;
856 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
857 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
862 if (r->route()->active()) {
869 items.push_back (CheckMenuElem (_("Active")));
870 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
871 bool click_sets_active = true;
872 if (active > 0 && inactive == 0) {
873 i->set_active (true);
874 click_sets_active = false;
875 } else if (active > 0 && inactive > 0) {
876 i->set_inconsistent (true);
878 i->set_sensitive(! _session->transport_rolling());
879 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), click_sets_active, true));
881 items.push_back (SeparatorElem());
882 items.push_back (MenuElem (_("Hide"), sigc::bind (sigc::mem_fun(_editor, &PublicEditor::hide_track_in_display), this, true)));
883 if (_route && !_route->is_master()) {
884 items.push_back (SeparatorElem());
885 items.push_back (MenuElem (_("Duplicate..."), boost::bind (&ARDOUR_UI::start_duplicate_routes, ARDOUR_UI::instance())));
887 items.push_back (SeparatorElem());
888 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(_editor, &PublicEditor::remove_tracks)));
892 RouteTimeAxisView::set_track_mode (TrackMode mode, bool apply_to_selection)
894 if (apply_to_selection) {
895 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_track_mode, _1, mode, false));
898 bool needs_bounce = false;
900 if (!track()->can_use_mode (mode, needs_bounce)) {
906 cerr << "would bounce this one\n";
911 track()->set_mode (mode);
916 RouteTimeAxisView::show_timestretch (framepos_t start, framepos_t end, int layers, int layer)
918 TimeAxisView::show_timestretch (start, end, layers, layer);
928 /* check that the time selection was made in our route, or our route group.
929 remember that route_group() == 0 implies the route is *not* in a edit group.
932 if (!(ts.track == this || (ts.group != 0 && ts.group == _route->route_group()))) {
933 /* this doesn't apply to us */
937 /* ignore it if our edit group is not active */
939 if ((ts.track != this) && _route->route_group() && !_route->route_group()->is_active()) {
944 if (timestretch_rect == 0) {
945 timestretch_rect = new ArdourCanvas::Rectangle (canvas_display ());
946 timestretch_rect->set_fill_color (ArdourCanvas::HSV (UIConfiguration::instance().color ("time stretch fill")).mod (UIConfiguration::instance().modifier ("time stretch fill")).color());
947 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
950 timestretch_rect->show ();
951 timestretch_rect->raise_to_top ();
953 double const x1 = start / _editor.get_current_zoom();
954 double const x2 = (end - 1) / _editor.get_current_zoom();
956 timestretch_rect->set (ArdourCanvas::Rect (x1, current_height() * (layers - layer - 1) / layers,
957 x2, current_height() * (layers - layer) / layers));
961 RouteTimeAxisView::hide_timestretch ()
963 TimeAxisView::hide_timestretch ();
965 if (timestretch_rect) {
966 timestretch_rect->hide ();
971 RouteTimeAxisView::show_selection (TimeSelection& ts)
975 /* ignore it if our edit group is not active or if the selection was started
976 in some other track or route group (remember that route_group() == 0 means
977 that the track is not in an route group).
980 if (((ts.track != this && !is_child (ts.track)) && _route->route_group() && !_route->route_group()->is_active()) ||
981 (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route->route_group())))) {
987 TimeAxisView::show_selection (ts);
991 RouteTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
994 bool height_changed = (height == 0) || (h != height);
997 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
1000 gm.get_level_meter().setup_meters (gmlen, meter_width);
1002 TimeAxisView::set_height (h, m);
1005 _view->set_height ((double) current_height());
1008 if (height >= preset_height (HeightNormal)) {
1012 gm.get_gain_slider().show();
1013 mute_button->show();
1014 if (!_route || _route->is_monitor()) {
1015 solo_button->hide();
1017 solo_button->show();
1019 if (rec_enable_button)
1020 rec_enable_button->show();
1022 route_group_button.show();
1023 automation_button.show();
1025 if (is_track() && track()->mode() == ARDOUR::Normal) {
1026 playlist_button.show();
1033 gm.get_gain_slider().hide();
1034 mute_button->show();
1035 if (!_route || _route->is_monitor()) {
1036 solo_button->hide();
1038 solo_button->show();
1040 if (rec_enable_button)
1041 rec_enable_button->show();
1043 route_group_button.hide ();
1044 automation_button.hide ();
1046 if (is_track() && track()->mode() == ARDOUR::Normal) {
1047 playlist_button.hide ();
1052 if (height_changed && !no_redraw) {
1053 /* only emit the signal if the height really changed */
1059 RouteTimeAxisView::route_color_changed ()
1062 _view->apply_color (color(), StreamView::RegionColor);
1065 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1069 RouteTimeAxisView::reset_samples_per_pixel ()
1071 set_samples_per_pixel (_editor.get_current_zoom());
1075 RouteTimeAxisView::set_samples_per_pixel (double fpp)
1080 speed = track()->speed();
1084 _view->set_samples_per_pixel (fpp * speed);
1087 TimeAxisView::set_samples_per_pixel (fpp * speed);
1091 RouteTimeAxisView::set_align_choice (RadioMenuItem* mitem, AlignChoice choice, bool apply_to_selection)
1093 if (!mitem->get_active()) {
1094 /* this is one of the two calls made when these radio menu items change status. this one
1095 is for the item that became inactive, and we want to ignore it.
1100 if (apply_to_selection) {
1101 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_align_choice, _1, mitem, choice, false));
1104 track()->set_align_choice (choice);
1110 RouteTimeAxisView::rename_current_playlist ()
1112 ArdourPrompter prompter (true);
1115 boost::shared_ptr<Track> tr = track();
1116 if (!tr || tr->destructive()) {
1120 boost::shared_ptr<Playlist> pl = tr->playlist();
1125 prompter.set_title (_("Rename Playlist"));
1126 prompter.set_prompt (_("New name for playlist:"));
1127 prompter.set_initial_text (pl->name());
1128 prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1129 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1131 switch (prompter.run ()) {
1132 case Gtk::RESPONSE_ACCEPT:
1133 prompter.get_result (name);
1134 if (name.length()) {
1135 pl->set_name (name);
1145 RouteTimeAxisView::resolve_new_group_playlist_name(std::string &basename, vector<boost::shared_ptr<Playlist> > const & playlists)
1147 std::string ret (basename);
1149 std::string const group_string = "." + route_group()->name() + ".";
1151 // iterate through all playlists
1153 for (vector<boost::shared_ptr<Playlist> >::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1154 std::string tmp = (*i)->name();
1156 std::string::size_type idx = tmp.find(group_string);
1157 // find those which belong to this group
1158 if (idx != string::npos) {
1159 tmp = tmp.substr(idx + group_string.length());
1161 // and find the largest current number
1163 if (x > maxnumber) {
1172 snprintf (buf, sizeof(buf), "%d", maxnumber);
1174 ret = this->name() + "." + route_group()->name () + "." + buf;
1180 RouteTimeAxisView::use_copy_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1184 boost::shared_ptr<Track> tr = track ();
1185 if (!tr || tr->destructive()) {
1189 boost::shared_ptr<const Playlist> pl = tr->playlist();
1196 if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1197 name = resolve_new_group_playlist_name(name, playlists_before_op);
1200 while (_session->playlists->by_name(name)) {
1201 name = Playlist::bump_name (name, *_session);
1204 // TODO: The prompter "new" button should be de-activated if the user
1205 // specifies a playlist name which already exists in the session.
1209 ArdourPrompter prompter (true);
1211 prompter.set_title (_("New Copy Playlist"));
1212 prompter.set_prompt (_("Name for new playlist:"));
1213 prompter.set_initial_text (name);
1214 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1215 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1216 prompter.show_all ();
1218 switch (prompter.run ()) {
1219 case Gtk::RESPONSE_ACCEPT:
1220 prompter.get_result (name);
1228 if (name.length()) {
1229 tr->use_copy_playlist ();
1230 tr->playlist()->set_name (name);
1235 RouteTimeAxisView::use_new_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1239 boost::shared_ptr<Track> tr = track ();
1240 if (!tr || tr->destructive()) {
1244 boost::shared_ptr<const Playlist> pl = tr->playlist();
1251 if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1252 name = resolve_new_group_playlist_name(name,playlists_before_op);
1255 while (_session->playlists->by_name(name)) {
1256 name = Playlist::bump_name (name, *_session);
1262 ArdourPrompter prompter (true);
1264 prompter.set_title (_("New Playlist"));
1265 prompter.set_prompt (_("Name for new playlist:"));
1266 prompter.set_initial_text (name);
1267 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1268 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1270 switch (prompter.run ()) {
1271 case Gtk::RESPONSE_ACCEPT:
1272 prompter.get_result (name);
1280 if (name.length()) {
1281 tr->use_new_playlist ();
1282 tr->playlist()->set_name (name);
1287 RouteTimeAxisView::clear_playlist ()
1289 boost::shared_ptr<Track> tr = track ();
1290 if (!tr || tr->destructive()) {
1294 boost::shared_ptr<Playlist> pl = tr->playlist();
1299 _editor.clear_playlist (pl);
1303 RouteTimeAxisView::speed_changed ()
1305 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&RouteTimeAxisView::reset_samples_per_pixel, this));
1309 RouteTimeAxisView::update_diskstream_display ()
1319 RouteTimeAxisView::selection_click (GdkEventButton* ev)
1321 if (Keyboard::modifier_state_equals (ev->state, (Keyboard::TertiaryModifier|Keyboard::PrimaryModifier))) {
1323 /* special case: select/deselect all tracks */
1325 _editor.begin_reversible_selection_op (X_("Selection Click"));
1327 if (_editor.get_selection().selected (this)) {
1328 _editor.get_selection().clear_tracks ();
1330 _editor.select_all_tracks ();
1333 _editor.commit_reversible_selection_op ();
1338 _editor.begin_reversible_selection_op (X_("Selection Click"));
1340 switch (ArdourKeyboard::selection_type (ev->state)) {
1341 case Selection::Toggle:
1342 _editor.get_selection().toggle (this);
1345 case Selection::Set:
1346 _editor.get_selection().set (this);
1349 case Selection::Extend:
1350 _editor.extend_selection_to_track (*this);
1353 case Selection::Add:
1354 _editor.get_selection().add (this);
1358 _editor.commit_reversible_selection_op ();
1362 RouteTimeAxisView::set_selected_points (PointSelection& points)
1364 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1365 (*i)->set_selected_points (points);
1367 AudioStreamView* asv = dynamic_cast<AudioStreamView*>(_view);
1369 asv->set_selected_points (points);
1374 RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
1377 _view->set_selected_regionviews (regions);
1381 /** Add the selectable things that we have to a list.
1382 * @param results List to add things to.
1385 RouteTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results, bool within)
1390 speed = track()->speed();
1393 framepos_t const start_adjusted = session_frame_to_track_frame(start, speed);
1394 framepos_t const end_adjusted = session_frame_to_track_frame(end, speed);
1396 if ((_view && ((top < 0.0 && bot < 0.0))) || touched (top, bot)) {
1397 _view->get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
1400 /* pick up visible automation tracks */
1402 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1403 if (!(*i)->hidden()) {
1404 (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results, within);
1410 RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
1413 _view->get_inverted_selectables (sel, results);
1416 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1417 if (!(*i)->hidden()) {
1418 (*i)->get_inverted_selectables (sel, results);
1426 RouteTimeAxisView::route_group () const
1428 return _route->route_group();
1431 boost::shared_ptr<Playlist>
1432 RouteTimeAxisView::playlist () const
1434 boost::shared_ptr<Track> tr;
1436 if ((tr = track()) != 0) {
1437 return tr->playlist();
1439 return boost::shared_ptr<Playlist> ();
1444 RouteTimeAxisView::name_entry_changed (string const& str)
1446 if (str == _route->name()) {
1452 strip_whitespace_edges (x);
1458 if (_session->route_name_internal (x)) {
1459 ARDOUR_UI::instance()->popup_error (string_compose (_("The name \"%1\" is reserved for %2"), x, PROGRAM_NAME));
1461 } else if (RouteUI::verify_new_route_name (x)) {
1462 _route->set_name (x);
1469 boost::shared_ptr<Region>
1470 RouteTimeAxisView::find_next_region (framepos_t pos, RegionPoint point, int32_t dir)
1472 boost::shared_ptr<Playlist> pl = playlist ();
1475 return pl->find_next_region (pos, point, dir);
1478 return boost::shared_ptr<Region> ();
1482 RouteTimeAxisView::find_next_region_boundary (framepos_t pos, int32_t dir)
1484 boost::shared_ptr<Playlist> pl = playlist ();
1487 return pl->find_next_region_boundary (pos, dir);
1494 RouteTimeAxisView::fade_range (TimeSelection& selection)
1496 boost::shared_ptr<Playlist> what_we_got;
1497 boost::shared_ptr<Track> tr = track ();
1498 boost::shared_ptr<Playlist> playlist;
1501 /* route is a bus, not a track */
1505 playlist = tr->playlist();
1507 TimeSelection time (selection);
1508 float const speed = tr->speed();
1509 if (speed != 1.0f) {
1510 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1511 (*i).start = session_frame_to_track_frame((*i).start, speed);
1512 (*i).end = session_frame_to_track_frame((*i).end, speed);
1516 playlist->clear_changes ();
1517 playlist->clear_owned_changes ();
1519 playlist->fade_range (time);
1521 vector<Command*> cmds;
1522 playlist->rdiff (cmds);
1523 _session->add_commands (cmds);
1524 _session->add_command (new StatefulDiffCommand (playlist));
1529 RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
1531 boost::shared_ptr<Playlist> what_we_got;
1532 boost::shared_ptr<Track> tr = track ();
1533 boost::shared_ptr<Playlist> playlist;
1536 /* route is a bus, not a track */
1540 playlist = tr->playlist();
1542 TimeSelection time (selection.time);
1543 float const speed = tr->speed();
1544 if (speed != 1.0f) {
1545 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1546 (*i).start = session_frame_to_track_frame((*i).start, speed);
1547 (*i).end = session_frame_to_track_frame((*i).end, speed);
1551 playlist->clear_changes ();
1552 playlist->clear_owned_changes ();
1556 if (playlist->cut (time) != 0) {
1557 if (Config->get_edit_mode() == Ripple)
1558 playlist->ripple(time.start(), -time.length(), NULL);
1559 // no need to exclude any regions from rippling here
1561 vector<Command*> cmds;
1562 playlist->rdiff (cmds);
1563 _session->add_commands (cmds);
1565 _session->add_command (new StatefulDiffCommand (playlist));
1570 if ((what_we_got = playlist->cut (time)) != 0) {
1571 _editor.get_cut_buffer().add (what_we_got);
1572 if (Config->get_edit_mode() == Ripple)
1573 playlist->ripple(time.start(), -time.length(), NULL);
1574 // no need to exclude any regions from rippling here
1576 vector<Command*> cmds;
1577 playlist->rdiff (cmds);
1578 _session->add_commands (cmds);
1580 _session->add_command (new StatefulDiffCommand (playlist));
1584 if ((what_we_got = playlist->copy (time)) != 0) {
1585 _editor.get_cut_buffer().add (what_we_got);
1590 if ((what_we_got = playlist->cut (time)) != 0) {
1591 if (Config->get_edit_mode() == Ripple)
1592 playlist->ripple(time.start(), -time.length(), NULL);
1593 // no need to exclude any regions from rippling here
1595 vector<Command*> cmds;
1596 playlist->rdiff (cmds);
1597 _session->add_commands (cmds);
1598 _session->add_command (new StatefulDiffCommand (playlist));
1599 what_we_got->release ();
1606 RouteTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1612 boost::shared_ptr<Playlist> pl = playlist ();
1613 const ARDOUR::DataType type = pl->data_type();
1614 PlaylistSelection::const_iterator p = selection.playlists.get_nth(type, ctx.counts.n_playlists(type));
1616 if (p == selection.playlists.end()) {
1619 ctx.counts.increase_n_playlists(type);
1621 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("paste to %1\n", pos));
1623 if (track()->speed() != 1.0f) {
1624 pos = session_frame_to_track_frame (pos, track()->speed());
1625 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("modified paste to %1\n", pos));
1628 /* add multi-paste offset if applicable */
1629 std::pair<framepos_t, framepos_t> extent = (*p)->get_extent();
1630 const framecnt_t duration = extent.second - extent.first;
1631 pos += _editor.get_paste_offset(pos, ctx.count, duration);
1633 pl->clear_changes ();
1634 pl->clear_owned_changes ();
1635 if (Config->get_edit_mode() == Ripple) {
1636 std::pair<framepos_t, framepos_t> extent = (*p)->get_extent_with_endspace();
1637 framecnt_t amount = extent.second - extent.first;
1638 pl->ripple(pos, amount * ctx.times, boost::shared_ptr<Region>());
1640 pl->paste (*p, pos, ctx.times, sub_num);
1642 vector<Command*> cmds;
1644 _session->add_commands (cmds);
1646 _session->add_command (new StatefulDiffCommand (pl));
1652 struct PlaylistSorter {
1653 bool operator() (boost::shared_ptr<Playlist> a, boost::shared_ptr<Playlist> b) const {
1654 return a->sort_id() < b->sort_id();
1659 RouteTimeAxisView::build_playlist_menu ()
1661 using namespace Menu_Helpers;
1667 delete playlist_action_menu;
1668 playlist_action_menu = new Menu;
1669 playlist_action_menu->set_name ("ArdourContextMenu");
1671 MenuList& playlist_items = playlist_action_menu->items();
1672 playlist_action_menu->set_name ("ArdourContextMenu");
1673 playlist_items.clear();
1675 RadioMenuItem::Group playlist_group;
1676 boost::shared_ptr<Track> tr = track ();
1678 vector<boost::shared_ptr<Playlist> > playlists_tr = _session->playlists->playlists_for_track (tr);
1680 /* sort the playlists */
1682 sort (playlists_tr.begin(), playlists_tr.end(), cmp);
1684 /* add the playlists to the menu */
1685 for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) {
1686 playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name()));
1687 RadioMenuItem *item = static_cast<RadioMenuItem*>(&playlist_items.back());
1688 item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist), item, boost::weak_ptr<Playlist> (*i)));
1690 if (tr->playlist()->id() == (*i)->id()) {
1696 playlist_items.push_back (SeparatorElem());
1697 playlist_items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
1698 playlist_items.push_back (SeparatorElem());
1700 if (!route_group() || !route_group()->is_active() || !route_group()->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1701 playlist_items.push_back (MenuElem (_("New..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1702 playlist_items.push_back (MenuElem (_("New Copy..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1705 // Use a label which tells the user what is happening
1706 playlist_items.push_back (MenuElem (_("New Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1707 playlist_items.push_back (MenuElem (_("Copy Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1711 playlist_items.push_back (SeparatorElem());
1712 playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::clear_playlists), this)));
1713 playlist_items.push_back (SeparatorElem());
1715 playlist_items.push_back (MenuElem(_("Select from All..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
1719 RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist> wpl)
1721 assert (is_track());
1723 // exit if we were triggered by deactivating the old playlist
1724 if (!item->get_active()) {
1728 boost::shared_ptr<Playlist> pl (wpl.lock());
1734 if (track()->playlist() == pl) {
1735 // exit when use_playlist is called by the creation of the playlist menu
1736 // or the playlist choice is unchanged
1740 track()->use_playlist (pl);
1742 RouteGroup* rg = route_group();
1744 if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1745 std::string group_string = "." + rg->name() + ".";
1747 std::string take_name = pl->name();
1748 std::string::size_type idx = take_name.find(group_string);
1750 if (idx == std::string::npos)
1753 take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
1755 boost::shared_ptr<RouteList> rl (rg->route_list());
1757 for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
1758 if ((*i) == this->route()) {
1762 std::string playlist_name = (*i)->name()+group_string+take_name;
1764 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
1769 if (track->freeze_state() == Track::Frozen) {
1770 /* Don't change playlists of frozen tracks */
1774 boost::shared_ptr<Playlist> ipl = session()->playlists->by_name(playlist_name);
1776 // No playlist for this track for this take yet, make it
1777 track->use_new_playlist();
1778 track->playlist()->set_name(playlist_name);
1780 track->use_playlist(ipl);
1787 RouteTimeAxisView::update_playlist_tip ()
1789 RouteGroup* rg = route_group ();
1790 if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1791 string group_string = "." + rg->name() + ".";
1793 string take_name = track()->playlist()->name();
1794 string::size_type idx = take_name.find(group_string);
1796 if (idx != string::npos) {
1797 /* find the bit containing the take number / name */
1798 take_name = take_name.substr (idx + group_string.length());
1800 /* set the playlist button tooltip to the take name */
1803 string_compose(_("Take: %1.%2"),
1804 Gtkmm2ext::markup_escape_text (rg->name()),
1805 Gtkmm2ext::markup_escape_text (take_name))
1812 /* set the playlist button tooltip to the playlist name */
1813 set_tooltip (playlist_button, _("Playlist") + std::string(": ") + Gtkmm2ext::markup_escape_text (track()->playlist()->name()));
1818 RouteTimeAxisView::show_playlist_selector ()
1820 _editor.playlist_selector().show_for (this);
1824 RouteTimeAxisView::map_frozen ()
1830 ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::map_frozen)
1832 switch (track()->freeze_state()) {
1834 playlist_button.set_sensitive (false);
1837 playlist_button.set_sensitive (true);
1840 RouteUI::map_frozen ();
1844 RouteTimeAxisView::color_handler ()
1846 //case cTimeStretchOutline:
1847 if (timestretch_rect) {
1848 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
1850 //case cTimeStretchFill:
1851 if (timestretch_rect) {
1852 timestretch_rect->set_fill_color (UIConfiguration::instance().color ("time stretch fill"));
1858 /** Toggle an automation track for a fully-specified Parameter (type,channel,id)
1859 * Will add track if necessary.
1862 RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
1864 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1865 Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1868 /* it doesn't exist yet, so we don't care about the button state: just add it */
1869 create_automation_child (param, true);
1872 bool yn = menu->get_active();
1873 bool changed = false;
1875 if ((changed = track->set_marked_for_display (menu->get_active())) && yn) {
1877 /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
1878 will have done that for us.
1881 if (changed && !no_redraw) {
1889 RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param)
1891 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1897 Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1899 if (menu && !_hidden) {
1900 ignore_toggle = true;
1901 menu->set_active (false);
1902 ignore_toggle = false;
1905 if (_route && !no_redraw) {
1911 RouteTimeAxisView::update_gain_track_visibility ()
1913 bool const showit = gain_automation_item->get_active();
1915 if (showit != string_is_affirmative (gain_track->gui_property ("visible"))) {
1916 gain_track->set_marked_for_display (showit);
1918 /* now trigger a redisplay */
1921 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1927 RouteTimeAxisView::update_trim_track_visibility ()
1929 bool const showit = trim_automation_item->get_active();
1931 if (showit != string_is_affirmative (trim_track->gui_property ("visible"))) {
1932 trim_track->set_marked_for_display (showit);
1934 /* now trigger a redisplay */
1937 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1943 RouteTimeAxisView::update_mute_track_visibility ()
1945 bool const showit = mute_automation_item->get_active();
1947 if (showit != string_is_affirmative (mute_track->gui_property ("visible"))) {
1948 mute_track->set_marked_for_display (showit);
1950 /* now trigger a redisplay */
1953 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1959 RouteTimeAxisView::update_pan_track_visibility ()
1961 bool const showit = pan_automation_item->get_active();
1962 bool changed = false;
1964 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1965 if ((*i)->set_marked_for_display (showit)) {
1971 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1976 RouteTimeAxisView::ensure_pan_views (bool show)
1978 bool changed = false;
1979 for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1981 (*i)->set_marked_for_display (false);
1984 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1988 if (!_route->panner()) {
1992 set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1993 set<Evoral::Parameter>::iterator p;
1995 for (p = params.begin(); p != params.end(); ++p) {
1996 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1998 if (pan_control->parameter().type() == NullAutomation) {
1999 error << "Pan control has NULL automation type!" << endmsg;
2003 if (automation_child (pan_control->parameter ()).get () == 0) {
2005 /* we don't already have an AutomationTimeAxisView for this parameter */
2007 std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
2009 boost::shared_ptr<AutomationTimeAxisView> t (
2010 new AutomationTimeAxisView (_session,
2014 pan_control->parameter (),
2022 pan_tracks.push_back (t);
2023 add_automation_child (*p, t, show);
2025 pan_tracks.push_back (automation_child (pan_control->parameter ()));
2032 RouteTimeAxisView::show_all_automation (bool apply_to_selection)
2034 if (apply_to_selection) {
2035 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_all_automation, _1, false));
2039 /* Show our automation */
2041 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2042 i->second->set_marked_for_display (true);
2044 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2047 menu->set_active(true);
2052 /* Show processor automation */
2054 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2055 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2056 if ((*ii)->view == 0) {
2057 add_processor_automation_curve ((*i)->processor, (*ii)->what);
2060 (*ii)->menu_item->set_active (true);
2073 RouteTimeAxisView::show_existing_automation (bool apply_to_selection)
2075 if (apply_to_selection) {
2076 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_existing_automation, _1, false));
2080 /* Show our automation */
2082 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2083 if (i->second->has_automation()) {
2084 i->second->set_marked_for_display (true);
2086 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2088 menu->set_active(true);
2093 /* Show processor automation */
2095 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2096 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2097 if ((*i)->processor->control((*ii)->what)->list()->size() > 0) {
2098 (*ii)->menu_item->set_active (true);
2110 RouteTimeAxisView::hide_all_automation (bool apply_to_selection)
2112 if (apply_to_selection) {
2113 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::hide_all_automation, _1, false));
2117 /* Hide our automation */
2119 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2120 i->second->set_marked_for_display (false);
2122 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2125 menu->set_active (false);
2129 /* Hide processor automation */
2131 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2132 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2133 (*ii)->menu_item->set_active (false);
2144 RouteTimeAxisView::region_view_added (RegionView* rv)
2146 /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
2147 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
2148 boost::shared_ptr<AutomationTimeAxisView> atv;
2150 if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
2155 for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
2156 (*i)->add_ghost(rv);
2160 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
2162 for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
2168 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
2170 parent.remove_processor_automation_node (this);
2174 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
2177 remove_child (pan->view);
2181 RouteTimeAxisView::ProcessorAutomationNode*
2182 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2184 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2186 if ((*i)->processor == processor) {
2188 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2189 if ((*ii)->what == what) {
2199 /** Add an AutomationTimeAxisView to display automation for a processor's parameter */
2201 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2204 ProcessorAutomationNode* pan;
2206 if ((pan = find_processor_automation_node (processor, what)) == 0) {
2207 /* session state may never have been saved with new plugin */
2208 error << _("programming error: ")
2209 << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"),
2210 processor->name(), what.type(), (int) what.channel(), what.id() )
2212 abort(); /*NOTREACHED*/
2220 boost::shared_ptr<AutomationControl> control
2221 = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
2223 pan->view = boost::shared_ptr<AutomationTimeAxisView>(
2224 new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (),
2225 _editor, *this, false, parent_canvas,
2226 processor->describe_parameter (what), processor->name()));
2228 pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
2230 add_automation_child (control->parameter(), pan->view, pan->view->marked_for_display ());
2233 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
2238 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor>)
2241 pan->menu_item->set_active (false);
2250 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
2252 boost::shared_ptr<Processor> processor (p.lock ());
2254 if (!processor || boost::dynamic_pointer_cast<Amp> (processor)) {
2255 /* The Amp processor is a special case and is dealt with separately */
2259 set<Evoral::Parameter> existing;
2261 processor->what_has_data (existing);
2263 for (set<Evoral::Parameter>::iterator i = existing.begin(); i != existing.end(); ++i) {
2265 Evoral::Parameter param (*i);
2266 boost::shared_ptr<AutomationLine> al;
2268 if ((al = find_processor_automation_curve (processor, param)) != 0) {
2271 add_processor_automation_curve (processor, param);
2277 RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show)
2279 using namespace Menu_Helpers;
2283 track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param));
2285 _automation_tracks[param] = track;
2287 /* existing state overrides "show" argument */
2288 string s = track->gui_property ("visible");
2290 show = string_is_affirmative (s);
2293 /* this might or might not change the visibility status, so don't rely on it */
2294 track->set_marked_for_display (show);
2296 if (show && !no_redraw) {
2300 if (!ARDOUR::parameter_is_midi((AutomationType)param.type())) {
2301 /* MIDI-related parameters are always in the menu, there's no
2302 reason to rebuild the menu just because we added a automation
2303 lane for one of them. But if we add a non-MIDI automation
2304 lane, then we need to invalidate the display menu.
2306 delete display_menu;
2312 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
2314 boost::shared_ptr<Processor> processor (p.lock ());
2316 if (!processor || !processor->display_to_user ()) {
2320 /* we use this override to veto the Amp processor from the plugin menu,
2321 as its automation lane can be accessed using the special "Fader" menu
2325 if (boost::dynamic_pointer_cast<Amp> (processor) != 0) {
2329 using namespace Menu_Helpers;
2330 ProcessorAutomationInfo *rai;
2331 list<ProcessorAutomationInfo*>::iterator x;
2333 const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
2335 if (automatable.empty()) {
2339 for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
2340 if ((*x)->processor == processor) {
2345 if (x == processor_automation.end()) {
2346 rai = new ProcessorAutomationInfo (processor);
2347 processor_automation.push_back (rai);
2352 /* any older menu was deleted at the top of processors_changed()
2353 when we cleared the subplugin menu.
2356 rai->menu = manage (new Menu);
2357 MenuList& items = rai->menu->items();
2358 rai->menu->set_name ("ArdourContextMenu");
2362 std::set<Evoral::Parameter> has_visible_automation;
2363 AutomationTimeAxisView::what_has_visible_automation (processor, has_visible_automation);
2365 for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2367 ProcessorAutomationNode* pan;
2368 Gtk::CheckMenuItem* mitem;
2370 string name = processor->describe_parameter (*i);
2372 if (name == X_("hidden")) {
2376 items.push_back (CheckMenuElem (name));
2377 mitem = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
2379 _subplugin_menu_map[*i] = mitem;
2381 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2382 mitem->set_active(true);
2385 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2389 pan = new ProcessorAutomationNode (*i, mitem, *this);
2391 rai->lines.push_back (pan);
2395 pan->menu_item = mitem;
2399 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2402 if (items.size() == 0) {
2406 /* add the menu for this processor, because the subplugin
2407 menu is always cleared at the top of processors_changed().
2408 this is the result of some poor design in gtkmm and/or
2412 subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2417 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2418 RouteTimeAxisView::ProcessorAutomationNode* pan)
2420 bool showit = pan->menu_item->get_active();
2421 bool redraw = false;
2423 if (pan->view == 0 && showit) {
2424 add_processor_automation_curve (rai->processor, pan->what);
2428 if (pan->view && pan->view->set_marked_for_display (showit)) {
2432 if (redraw && !no_redraw) {
2438 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2440 if (c.type == RouteProcessorChange::MeterPointChange) {
2441 /* nothing to do if only the meter point has changed */
2445 using namespace Menu_Helpers;
2447 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2448 (*i)->valid = false;
2451 setup_processor_menu_and_curves ();
2453 bool deleted_processor_automation = false;
2455 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2457 list<ProcessorAutomationInfo*>::iterator tmp;
2465 processor_automation.erase (i);
2466 deleted_processor_automation = true;
2473 if (deleted_processor_automation && !no_redraw) {
2478 boost::shared_ptr<AutomationLine>
2479 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2481 ProcessorAutomationNode* pan;
2483 if ((pan = find_processor_automation_node (processor, what)) != 0) {
2489 return boost::shared_ptr<AutomationLine>();
2493 RouteTimeAxisView::reset_processor_automation_curves ()
2495 for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2501 RouteTimeAxisView::can_edit_name () const
2503 /* we do not allow track name changes if it is record enabled
2505 boost::shared_ptr<Track> trk (boost::dynamic_pointer_cast<Track> (_route));
2509 return !trk->rec_enable_control()->get_value();
2513 RouteTimeAxisView::blink_rec_display (bool onoff)
2515 RouteUI::blink_rec_display (onoff);
2519 RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection)
2521 if (_ignore_set_layer_display) {
2525 if (apply_to_selection) {
2526 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false));
2530 _view->set_layer_display (d);
2533 set_gui_property (X_("layer-display"), enum_2_string (d));
2538 RouteTimeAxisView::layer_display () const
2541 return _view->layer_display ();
2544 /* we don't know, since we don't have a _view, so just return something */
2550 boost::shared_ptr<AutomationTimeAxisView>
2551 RouteTimeAxisView::automation_child(Evoral::Parameter param)
2553 AutomationTracks::iterator i = _automation_tracks.find(param);
2554 if (i != _automation_tracks.end()) {
2557 return boost::shared_ptr<AutomationTimeAxisView>();
2562 RouteTimeAxisView::fast_update ()
2564 gm.get_level_meter().update_meters ();
2568 RouteTimeAxisView::hide_meter ()
2571 gm.get_level_meter().hide_meters ();
2575 RouteTimeAxisView::show_meter ()
2581 RouteTimeAxisView::reset_meter ()
2583 if (UIConfiguration::instance().get_show_track_meters()) {
2584 int meter_width = 3;
2585 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
2588 gm.get_level_meter().setup_meters (height - 9, meter_width);
2595 RouteTimeAxisView::clear_meter ()
2597 gm.get_level_meter().clear_meters ();
2601 RouteTimeAxisView::meter_changed ()
2603 ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed)
2605 if (_route && !no_redraw && UIConfiguration::instance().get_show_track_meters()) {
2608 // reset peak when meter point changes
2609 gm.reset_peak_display();
2613 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2616 if (_route && !no_redraw) {
2622 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu)
2624 using namespace Menu_Helpers;
2626 if (!_underlay_streams.empty()) {
2627 MenuList& parent_items = parent_menu->items();
2628 Menu* gs_menu = manage (new Menu);
2629 gs_menu->set_name ("ArdourContextMenu");
2630 MenuList& gs_items = gs_menu->items();
2632 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2634 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2635 gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2636 sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2642 RouteTimeAxisView::set_underlay_state()
2644 if (!underlay_xml_node) {
2648 XMLNodeList nlist = underlay_xml_node->children();
2649 XMLNodeConstIterator niter;
2650 XMLNode *child_node;
2652 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2653 child_node = *niter;
2655 if (child_node->name() != "Underlay") {
2659 XMLProperty const * prop = child_node->property ("id");
2661 PBD::ID id (prop->value());
2663 RouteTimeAxisView* v = _editor.get_route_view_by_route_id (id);
2666 add_underlay(v->view(), false);
2675 RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/)
2681 RouteTimeAxisView& other = v->trackview();
2683 if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2684 if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2685 fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2686 abort(); /*NOTREACHED*/
2689 _underlay_streams.push_back(v);
2690 other._underlay_mirrors.push_back(this);
2692 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2694 #ifdef GUI_OBJECT_STATE_FIX_REQUIRED
2696 if (!underlay_xml_node) {
2697 underlay_xml_node = xml_node->add_child("Underlays");
2700 XMLNode* node = underlay_xml_node->add_child("Underlay");
2701 XMLProperty const * prop = node->add_property("id");
2702 prop->set_value(v->trackview().route()->id().to_s());
2709 RouteTimeAxisView::remove_underlay (StreamView* v)
2715 UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2716 RouteTimeAxisView& other = v->trackview();
2718 if (it != _underlay_streams.end()) {
2719 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2721 if (gm == other._underlay_mirrors.end()) {
2722 fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2723 abort(); /*NOTREACHED*/
2726 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2728 _underlay_streams.erase(it);
2729 other._underlay_mirrors.erase(gm);
2731 if (underlay_xml_node) {
2732 underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2738 RouteTimeAxisView::set_button_names ()
2740 if (_route && _route->solo_safe_control()->solo_safe()) {
2741 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2743 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2745 if (Config->get_solo_control_is_listen_control()) {
2746 switch (Config->get_listen_position()) {
2747 case AfterFaderListen:
2748 solo_button->set_text (S_("AfterFader|A"));
2749 set_tooltip (*solo_button, _("After-fade listen (AFL)"));
2751 case PreFaderListen:
2752 solo_button->set_text (S_("PreFader|P"));
2753 set_tooltip (*solo_button, _("Pre-fade listen (PFL)"));
2757 solo_button->set_text (S_("Solo|S"));
2758 set_tooltip (*solo_button, _("Solo"));
2760 mute_button->set_text (S_("Mute|M"));
2764 RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
2766 ParameterMenuMap::iterator i = _main_automation_menu_map.find (param);
2767 if (i != _main_automation_menu_map.end()) {
2771 i = _subplugin_menu_map.find (param);
2772 if (i != _subplugin_menu_map.end()) {
2780 RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, bool show)
2782 boost::shared_ptr<AutomationControl> c = _route->gain_control();
2784 error << "Route has no gain automation, unable to add automation track view." << endmsg;
2788 gain_track.reset (new AutomationTimeAxisView (_session,
2789 _route, _route->amp(), c, param,
2794 _route->amp()->describe_parameter(param)));
2797 _view->foreach_regionview (sigc::mem_fun (*gain_track.get(), &TimeAxisView::add_ghost));
2800 add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
2804 RouteTimeAxisView::create_trim_automation_child (const Evoral::Parameter& param, bool show)
2806 boost::shared_ptr<AutomationControl> c = _route->trim()->gain_control();
2807 if (!c || ! _route->trim()->active()) {
2811 trim_track.reset (new AutomationTimeAxisView (_session,
2812 _route, _route->trim(), c, param,
2817 _route->trim()->describe_parameter(param)));
2820 _view->foreach_regionview (sigc::mem_fun (*trim_track.get(), &TimeAxisView::add_ghost));
2823 add_automation_child (Evoral::Parameter(TrimAutomation), trim_track, show);
2827 RouteTimeAxisView::create_mute_automation_child (const Evoral::Parameter& param, bool show)
2829 boost::shared_ptr<AutomationControl> c = _route->mute_control();
2831 error << "Route has no mute automation, unable to add automation track view." << endmsg;
2835 mute_track.reset (new AutomationTimeAxisView (_session,
2836 _route, _route, c, param,
2841 _route->describe_parameter(param)));
2844 _view->foreach_regionview (sigc::mem_fun (*mute_track.get(), &TimeAxisView::add_ghost));
2847 add_automation_child (Evoral::Parameter(MuteAutomation), mute_track, show);
2851 void add_region_to_list (RegionView* rv, RegionList* l)
2853 l->push_back (rv->region());
2857 RouteTimeAxisView::combine_regions ()
2859 /* as of may 2011, we do not offer uncombine for MIDI tracks
2862 if (!is_audio_track()) {
2870 RegionList selected_regions;
2871 boost::shared_ptr<Playlist> playlist = track()->playlist();
2873 _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2875 if (selected_regions.size() < 2) {
2879 playlist->clear_changes ();
2880 boost::shared_ptr<Region> compound_region = playlist->combine (selected_regions);
2882 _session->add_command (new StatefulDiffCommand (playlist));
2883 /* make the new region be selected */
2885 return _view->find_view (compound_region);
2889 RouteTimeAxisView::uncombine_regions ()
2891 /* as of may 2011, we do not offer uncombine for MIDI tracks
2893 if (!is_audio_track()) {
2901 RegionList selected_regions;
2902 boost::shared_ptr<Playlist> playlist = track()->playlist();
2904 /* have to grab selected regions first because the uncombine is going
2905 * to change that in the middle of the list traverse
2908 _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2910 playlist->clear_changes ();
2912 for (RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) {
2913 playlist->uncombine (*i);
2916 _session->add_command (new StatefulDiffCommand (playlist));
2920 RouteTimeAxisView::state_id() const
2922 return string_compose ("rtav %1", _route->id().to_s());
2927 RouteTimeAxisView::remove_child (boost::shared_ptr<TimeAxisView> c)
2929 TimeAxisView::remove_child (c);
2931 boost::shared_ptr<AutomationTimeAxisView> a = boost::dynamic_pointer_cast<AutomationTimeAxisView> (c);
2933 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2934 if (i->second == a) {
2935 _automation_tracks.erase (i);
2943 RouteTimeAxisView::color () const
2945 return route_color ();
2949 RouteTimeAxisView::marked_for_display () const
2951 return !_route->presentation_info().hidden();
2955 RouteTimeAxisView::set_marked_for_display (bool yn)
2957 return RouteUI::mark_hidden (!yn);