2 Copyright (C) 2000-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.
23 #include "pbd/stacktrace.h"
25 #include "ardour/session.h"
26 #include "ardour/playlist.h"
27 #include "ardour/route_group.h"
28 #include "ardour/profile.h"
29 #include "ardour/midi_region.h"
33 #include "audio_time_axis.h"
34 #include "audio_region_view.h"
35 #include "audio_streamview.h"
36 #include "automation_line.h"
37 #include "control_point.h"
38 #include "editor_regions.h"
39 #include "editor_cursors.h"
40 #include "midi_region_view.h"
45 using namespace ARDOUR;
49 using namespace Gtkmm2ext;
50 using namespace Editing;
52 struct TrackViewByPositionSorter
54 bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
55 return a->y_position() < b->y_position();
60 Editor::extend_selection_to_track (TimeAxisView& view)
62 if (selection->selected (&view)) {
63 /* already selected, do nothing */
67 if (selection->tracks.empty()) {
69 if (!selection->selected (&view)) {
70 selection->set (&view);
77 /* something is already selected, so figure out which range of things to add */
79 TrackViewList to_be_added;
80 TrackViewList sorted = track_views;
81 TrackViewByPositionSorter cmp;
82 bool passed_clicked = false;
87 if (!selection->selected (&view)) {
88 to_be_added.push_back (&view);
91 /* figure out if we should go forward or backwards */
93 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
96 passed_clicked = true;
99 if (selection->selected (*i)) {
100 if (passed_clicked) {
109 passed_clicked = false;
113 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
116 passed_clicked = true;
120 if (passed_clicked) {
121 if ((*i)->hidden()) {
124 if (selection->selected (*i)) {
126 } else if (!(*i)->hidden()) {
127 to_be_added.push_back (*i);
134 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
137 passed_clicked = true;
141 if (passed_clicked) {
143 if ((*r)->hidden()) {
147 if (selection->selected (*r)) {
149 } else if (!(*r)->hidden()) {
150 to_be_added.push_back (*r);
156 if (!to_be_added.empty()) {
157 selection->add (to_be_added);
165 Editor::select_all_tracks ()
167 TrackViewList visible_views;
168 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
169 if ((*i)->marked_for_display()) {
170 visible_views.push_back (*i);
173 selection->set (visible_views);
176 /** Select clicked_axisview, unless there are no currently selected
177 * tracks, in which case nothing will happen unless `force' is true.
180 Editor::set_selected_track_as_side_effect (Selection::Operation op, bool /*force*/)
182 if (!clicked_axisview) {
187 if (!clicked_routeview) {
191 bool had_tracks = !selection->tracks.empty();
192 RouteGroup* group = clicked_routeview->route()->route_group();
193 RouteGroup& arg (_session->all_route_group());
196 case Selection::Toggle:
197 if (selection->selected (clicked_axisview)) {
198 if (arg.is_select() && arg.is_active()) {
199 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
200 selection->remove(*i);
202 } else if (group && group->is_active()) {
203 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
204 if ((*i)->route_group() == group)
205 selection->remove(*i);
208 selection->remove (clicked_axisview);
211 if (arg.is_select() && arg.is_active()) {
212 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
215 } else if (group && group->is_active()) {
216 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
217 if ( (*i)->route_group() == group)
221 selection->add (clicked_axisview);
227 if (!had_tracks && arg.is_select() && arg.is_active()) {
228 /* nothing was selected already, and all group is active etc. so use
231 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
234 } else if (group && group->is_active()) {
235 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
236 if ((*i)->route_group() == group)
240 selection->add (clicked_axisview);
246 if (!had_tracks && arg.is_select() && arg.is_active()) {
247 /* nothing was selected already, and all group is active etc. so use
250 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
253 } else if (group && group->is_active()) {
254 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
255 if ((*i)->route_group() == group)
259 selection->set (clicked_axisview);
263 case Selection::Extend:
265 cerr << ("Editor::set_selected_track_as_side_effect case Selection::Add not yet implemented\n");
269 #else // the older version
271 if (!selection->tracks.empty()) {
272 if (!selection->selected (clicked_axisview)) {
273 selection->add (clicked_axisview);
277 selection->set (clicked_axisview);
283 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
286 case Selection::Toggle:
287 if (selection->selected (&view)) {
289 selection->remove (&view);
292 selection->add (&view);
297 if (!selection->selected (&view)) {
298 selection->add (&view);
303 selection->set (&view);
306 case Selection::Extend:
307 extend_selection_to_track (view);
313 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
315 if (!clicked_routeview) {
323 set_selected_track (*clicked_routeview, op, no_remove);
327 Editor::set_selected_control_point_from_click (Selection::Operation op, bool /*no_remove*/)
329 if (!clicked_control_point) {
335 selection->set (clicked_control_point);
338 selection->add (clicked_control_point);
340 case Selection::Toggle:
341 selection->toggle (clicked_control_point);
343 case Selection::Extend:
352 Editor::get_onscreen_tracks (TrackViewList& tvl)
354 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
355 if ((*i)->y_position() < _canvas_height) {
361 /** Call a slot for a given `basis' track and also for any track that is in the same
362 * active route group with a particular set of properties.
364 * @param sl Slot to call.
365 * @param basis Basis track.
366 * @param prop Properties that active edit groups must share to be included in the map.
370 Editor::mapover_tracks (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
372 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
374 if (route_basis == 0) {
378 set<RouteTimeAxisView*> tracks;
379 tracks.insert (route_basis);
381 RouteGroup* group = route_basis->route()->route_group();
383 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id) ) {
385 /* the basis is a member of an active route group, with the appropriate
386 properties; find other members */
388 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
389 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
390 if (v && v->route()->route_group() == group) {
397 uint32_t const sz = tracks.size ();
399 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
405 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
407 boost::shared_ptr<Playlist> pl;
408 vector<boost::shared_ptr<Region> > results;
410 boost::shared_ptr<Track> tr;
412 if ((tr = tv.track()) == 0) {
417 if (&tv == &basis->get_time_axis_view()) {
418 /* looking in same track as the original */
422 if ((pl = tr->playlist()) != 0) {
423 pl->get_equivalent_regions (basis->region(), results);
426 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
427 if ((marv = tv.view()->find_view (*ir)) != 0) {
428 all_equivs->push_back (marv);
434 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, PBD::PropertyID property) const
436 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_time_axis_view(), property);
438 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
440 equivalent_regions.push_back (basis);
444 Editor::get_equivalent_regions (RegionSelection & basis, PBD::PropertyID prop) const
446 RegionSelection equivalent;
448 for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
450 vector<RegionView*> eq;
453 sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
454 &(*i)->get_time_axis_view(), prop);
456 for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
468 Editor::get_regionview_count_from_region_list (boost::shared_ptr<Region> region)
470 int region_count = 0;
472 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
474 RouteTimeAxisView* tatv;
476 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
478 boost::shared_ptr<Playlist> pl;
479 vector<boost::shared_ptr<Region> > results;
481 boost::shared_ptr<Track> tr;
483 if ((tr = tatv->track()) == 0) {
488 if ((pl = (tr->playlist())) != 0) {
489 pl->get_region_list_equivalent_regions (region, results);
492 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
493 if ((marv = tatv->view()->find_view (*ir)) != 0) {
506 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool /*no_track_remove*/)
508 vector<RegionView*> all_equivalent_regions;
511 if (!clicked_regionview || !clicked_routeview) {
516 button_release_can_deselect = false;
519 if (op == Selection::Toggle || op == Selection::Set) {
523 case Selection::Toggle:
524 if (selection->selected (clicked_regionview)) {
527 /* whatever was clicked was selected already; do nothing here but allow
528 the button release to deselect it
531 button_release_can_deselect = true;
534 if (button_release_can_deselect) {
536 /* just remove this one region, but only on a permitted button release */
538 selection->remove (clicked_regionview);
541 /* no more deselect action on button release till a new press
542 finds an already selected object.
545 button_release_can_deselect = false;
553 if (selection->selected (clicked_routeview)) {
554 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
556 all_equivalent_regions.push_back (clicked_regionview);
559 /* add all the equivalent regions, but only on button press */
561 if (!all_equivalent_regions.empty()) {
565 selection->add (all_equivalent_regions);
571 if (!selection->selected (clicked_regionview)) {
572 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
573 selection->set (all_equivalent_regions);
576 /* no commit necessary: clicked on an already selected region */
586 } else if (op == Selection::Extend) {
588 list<Selectable*> results;
589 framepos_t last_frame;
590 framepos_t first_frame;
591 bool same_track = false;
593 /* 1. find the last selected regionview in the track that was clicked in */
596 first_frame = max_framepos;
598 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
599 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
601 if ((*x)->region()->last_frame() > last_frame) {
602 last_frame = (*x)->region()->last_frame();
605 if ((*x)->region()->first_frame() < first_frame) {
606 first_frame = (*x)->region()->first_frame();
615 /* 2. figure out the boundaries for our search for new objects */
617 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
619 if (last_frame < clicked_regionview->region()->first_frame()) {
620 first_frame = last_frame;
621 last_frame = clicked_regionview->region()->last_frame();
623 last_frame = first_frame;
624 first_frame = clicked_regionview->region()->first_frame();
628 case OverlapExternal:
629 if (last_frame < clicked_regionview->region()->first_frame()) {
630 first_frame = last_frame;
631 last_frame = clicked_regionview->region()->last_frame();
633 last_frame = first_frame;
634 first_frame = clicked_regionview->region()->first_frame();
638 case OverlapInternal:
639 if (last_frame < clicked_regionview->region()->first_frame()) {
640 first_frame = last_frame;
641 last_frame = clicked_regionview->region()->last_frame();
643 last_frame = first_frame;
644 first_frame = clicked_regionview->region()->first_frame();
650 /* nothing to do except add clicked region to selection, since it
651 overlaps with the existing selection in this track.
658 /* click in a track that has no regions selected, so extend vertically
659 to pick out all regions that are defined by the existing selection
664 first_frame = clicked_regionview->region()->position();
665 last_frame = clicked_regionview->region()->last_frame();
667 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
668 if ((*i)->region()->position() < first_frame) {
669 first_frame = (*i)->region()->position();
671 if ((*i)->region()->last_frame() + 1 > last_frame) {
672 last_frame = (*i)->region()->last_frame();
677 /* 2. find all the tracks we should select in */
679 set<RouteTimeAxisView*> relevant_tracks;
681 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
682 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
684 relevant_tracks.insert (r);
688 set<RouteTimeAxisView*> already_in_selection;
690 if (relevant_tracks.empty()) {
692 /* no tracks selected .. thus .. if the
693 regionview we're in isn't selected
694 (i.e. we're about to extend to it), then
695 find all tracks between the this one and
699 if (!selection->selected (clicked_regionview)) {
701 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&clicked_regionview->get_time_axis_view());
705 /* add this track to the ones we will search */
707 relevant_tracks.insert (rtv);
709 /* find the track closest to this one that
710 already a selected region.
713 RouteTimeAxisView* closest = 0;
714 int distance = INT_MAX;
715 int key = rtv->route()->order_key ("editor");
717 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
719 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
721 if (artv && artv != rtv) {
723 pair<set<RouteTimeAxisView*>::iterator,bool> result;
725 result = already_in_selection.insert (artv);
728 /* newly added to already_in_selection */
730 int d = artv->route()->order_key ("editor");
734 if (abs (d) < distance) {
744 /* now add all tracks between that one and this one */
746 int okey = closest->route()->order_key ("editor");
752 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
753 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
754 if (artv && artv != rtv) {
756 int k = artv->route()->order_key ("editor");
758 if (k >= okey && k <= key) {
760 /* in range but don't add it if
761 it already has tracks selected.
762 this avoids odd selection
763 behaviour that feels wrong.
766 if (find (already_in_selection.begin(),
767 already_in_selection.end(),
768 artv) == already_in_selection.end()) {
770 relevant_tracks.insert (artv);
780 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
781 one that was clicked.
784 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
785 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
788 /* 4. convert to a vector of regions */
790 vector<RegionView*> regions;
792 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
795 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
796 regions.push_back (arv);
800 if (!regions.empty()) {
801 selection->add (regions);
812 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
814 vector<RegionView*> all_equivalent_regions;
816 get_regions_corresponding_to (region, all_equivalent_regions);
818 if (all_equivalent_regions.empty()) {
822 begin_reversible_command (_("set selected regions"));
825 case Selection::Toggle:
826 /* XXX this is not correct */
827 selection->toggle (all_equivalent_regions);
830 selection->set (all_equivalent_regions);
832 case Selection::Extend:
833 selection->add (all_equivalent_regions);
836 selection->add (all_equivalent_regions);
840 commit_reversible_command () ;
844 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
847 boost::shared_ptr<Region> r (weak_r.lock());
853 if ((rv = sv->find_view (r)) == 0) {
857 /* don't reset the selection if its something other than
858 a single other region.
861 if (selection->regions.size() > 1) {
865 begin_reversible_command (_("set selected regions"));
869 commit_reversible_command () ;
875 Editor::track_selection_changed ()
877 switch (selection->tracks.size()) {
881 set_selected_mixer_strip (*(selection->tracks.front()));
885 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
887 bool yn = (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end());
889 (*i)->set_selected (yn);
891 TimeAxisView::Children c = (*i)->get_child_list ();
892 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
893 (*j)->set_selected (find (selection->tracks.begin(), selection->tracks.end(), j->get()) != selection->tracks.end());
897 ((mouse_mode == MouseRange) ||
898 ((mouse_mode == MouseObject) && (_join_object_range_state == JOIN_OBJECT_RANGE_OBJECT)))) {
899 (*i)->reshow_selection (selection->time);
901 (*i)->hide_selection ();
905 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
909 Editor::time_selection_changed ()
911 if (Profile->get_sae()) {
915 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
916 (*i)->hide_selection ();
919 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
920 (*i)->show_selection (selection->time);
923 if (selection->time.empty()) {
924 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
926 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
930 /** Set all region actions to have a given sensitivity */
932 Editor::sensitize_all_region_actions (bool s)
934 Glib::ListHandle<Glib::RefPtr<Action> > all = _region_actions->get_actions ();
936 for (Glib::ListHandle<Glib::RefPtr<Action> >::iterator i = all.begin(); i != all.end(); ++i) {
937 (*i)->set_sensitive (s);
940 _all_region_actions_sensitized = s;
943 /** Sensitize region-based actions based on the selection ONLY, ignoring the entered_regionview.
944 * This method should be called just before displaying a Region menu. When a Region menu is not
945 * currently being shown, all region actions are sensitized so that hotkey-triggered actions
946 * on entered_regionviews work without having to check sensitivity every time the selection or
947 * entered_regionview changes.
949 * This method also sets up toggle action state as appropriate.
952 Editor::sensitize_the_right_region_actions ()
954 if ((mouse_mode == MouseRange) || (mouse_mode != MouseObject && _join_object_range_state == JOIN_OBJECT_RANGE_RANGE)) {
955 sensitize_all_region_actions (false);
956 if (!selection->time.empty()) {
957 _region_actions->get_action("split-region")->set_sensitive (true);
961 } else if (mouse_mode != MouseObject) {
962 sensitize_all_region_actions (false);
966 /* We get here if we are in Object mode */
968 RegionSelection rs = get_regions_from_selection_and_entered ();
969 sensitize_all_region_actions (!rs.empty ());
971 _ignore_region_action = true;
973 /* Look through the regions that are selected and make notes about what we have got */
975 bool have_audio = false;
976 bool have_multichannel_audio = false;
977 bool have_midi = false;
978 bool have_locked = false;
979 bool have_unlocked = false;
980 bool have_position_lock_style_audio = false;
981 bool have_position_lock_style_music = false;
982 bool have_muted = false;
983 bool have_unmuted = false;
984 bool have_opaque = false;
985 bool have_non_opaque = false;
986 bool have_not_at_natural_position = false;
987 bool have_envelope_visible = false;
988 bool have_envelope_invisible = false;
989 bool have_envelope_active = false;
990 bool have_envelope_inactive = false;
991 bool have_non_unity_scale_amplitude = false;
992 bool have_compound_regions = false;
994 for (list<RegionView*>::const_iterator i = rs.begin(); i != rs.end(); ++i) {
996 boost::shared_ptr<Region> r = (*i)->region ();
997 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
1001 if (ar->n_channels() > 1) {
1002 have_multichannel_audio = true;
1006 if (boost::dynamic_pointer_cast<MidiRegion> (r)) {
1010 if (r->is_compound()) {
1011 have_compound_regions = true;
1017 have_unlocked = true;
1020 if (r->position_lock_style() == MusicTime) {
1021 have_position_lock_style_music = true;
1023 have_position_lock_style_audio = true;
1029 have_unmuted = true;
1035 have_non_opaque = true;
1038 if (!r->at_natural_position()) {
1039 have_not_at_natural_position = true;
1043 /* its a bit unfortunate that "envelope visible" is a view-only
1044 property. we have to find the regionview to able to check
1045 its current setting.
1048 have_envelope_invisible = true;
1051 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
1052 if (arv && arv->envelope_visible()) {
1053 have_envelope_visible = true;
1057 if (ar->envelope_active()) {
1058 have_envelope_active = true;
1060 have_envelope_inactive = true;
1063 if (ar->scale_amplitude() != 1) {
1064 have_non_unity_scale_amplitude = true;
1069 if (rs.size() > 1) {
1070 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1071 _region_actions->get_action("show-region-properties")->set_sensitive (false);
1072 _region_actions->get_action("rename-region")->set_sensitive (false);
1074 _region_actions->get_action("combine-regions")->set_sensitive (true);
1076 _region_actions->get_action("combine-regions")->set_sensitive (false);
1078 } else if (rs.size() == 1) {
1079 _region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
1080 _region_actions->get_action("close-region-gaps")->set_sensitive (false);
1081 _region_actions->get_action("combine-regions")->set_sensitive (false);
1084 if (!have_multichannel_audio) {
1085 _region_actions->get_action("split-multichannel-region")->set_sensitive (false);
1089 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1090 _region_actions->get_action("quantize-region")->set_sensitive (false);
1091 _region_actions->get_action("fork-region")->set_sensitive (false);
1092 _region_actions->get_action("transpose-region")->set_sensitive (false);
1095 if (_edit_point == EditAtMouse) {
1096 _region_actions->get_action("set-region-sync-position")->set_sensitive (false);
1097 _region_actions->get_action("trim-front")->set_sensitive (false);
1098 _region_actions->get_action("trim-back")->set_sensitive (false);
1099 _region_actions->get_action("split-region")->set_sensitive (false);
1100 _region_actions->get_action("place-transient")->set_sensitive (false);
1103 if (have_compound_regions) {
1104 _region_actions->get_action("uncombine-regions")->set_sensitive (true);
1106 _region_actions->get_action("uncombine-regions")->set_sensitive (false);
1111 if (have_envelope_visible && !have_envelope_invisible) {
1112 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-visible"))->set_active ();
1113 } else if (have_envelope_visible && have_envelope_invisible) {
1114 // _region_actions->get_action("toggle-region-gain-envelope-visible")->set_inconsistent ();
1117 if (have_envelope_active && !have_envelope_inactive) {
1118 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active ();
1119 } else if (have_envelope_active && have_envelope_inactive) {
1120 // _region_actions->get_action("toggle-region-gain-envelope-active")->set_inconsistent ();
1125 _region_actions->get_action("analyze-region")->set_sensitive (false);
1126 _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
1127 _region_actions->get_action("toggle-region-gain-envelope-visible")->set_sensitive (false);
1128 _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
1129 _region_actions->get_action("pitch-shift-region")->set_sensitive (false);
1133 if (!have_non_unity_scale_amplitude || !have_audio) {
1134 _region_actions->get_action("reset-region-scale-amplitude")->set_sensitive (false);
1137 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"))->set_active (have_locked && !have_unlocked);
1138 if (have_locked && have_unlocked) {
1139 // _region_actions->get_action("toggle-region-lock")->set_inconsistent ();
1142 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"))->set_active (have_position_lock_style_music && !have_position_lock_style_audio);
1144 if (have_position_lock_style_music && have_position_lock_style_audio) {
1145 // _region_actions->get_action("toggle-region-lock-style")->set_inconsistent ();
1148 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"))->set_active (have_muted && !have_unmuted);
1149 if (have_muted && have_unmuted) {
1150 // _region_actions->get_action("toggle-region-mute")->set_inconsistent ();
1153 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"))->set_active (have_opaque && !have_non_opaque);
1154 if (have_opaque && have_non_opaque) {
1155 // _region_actions->get_action("toggle-opaque-region")->set_inconsistent ();
1158 if (!have_not_at_natural_position) {
1159 _region_actions->get_action("naturalize-region")->set_sensitive (false);
1162 /* XXX: should also check that there is a track of the appropriate type for the selected region */
1163 if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
1164 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (false);
1166 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (true);
1169 _ignore_region_action = false;
1171 _all_region_actions_sensitized = false;
1176 Editor::region_selection_changed ()
1178 _regions->block_change_connection (true);
1179 editor_regions_selection_changed_connection.block(true);
1181 if (_region_selection_change_updates_region_list) {
1182 _regions->unselect_all ();
1185 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1186 (*i)->set_selected_regionviews (selection->regions);
1189 if (_region_selection_change_updates_region_list) {
1190 _regions->set_selected (selection->regions);
1193 _regions->block_change_connection (false);
1194 editor_regions_selection_changed_connection.block(false);
1196 if (!_all_region_actions_sensitized) {
1197 /* This selection change might have changed what region actions
1198 are allowed, so sensitize them all in case a key is pressed.
1200 sensitize_all_region_actions (true);
1205 Editor::point_selection_changed ()
1207 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1208 (*i)->set_selected_points (selection->points);
1213 Editor::select_all_in_track (Selection::Operation op)
1215 list<Selectable *> touched;
1217 if (!clicked_routeview) {
1221 clicked_routeview->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1224 case Selection::Toggle:
1225 selection->add (touched);
1227 case Selection::Set:
1228 selection->set (touched);
1230 case Selection::Extend:
1231 /* meaningless, because we're selecting everything */
1233 case Selection::Add:
1234 selection->add (touched);
1240 Editor::select_all_internal_edit (Selection::Operation)
1242 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1243 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1245 mrv->select_all_notes ();
1251 Editor::select_all (Selection::Operation op)
1253 list<Selectable *> touched;
1255 if (_internal_editing) {
1256 select_all_internal_edit (op);
1260 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1261 if ((*iter)->hidden()) {
1264 (*iter)->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1266 begin_reversible_command (_("select all"));
1268 case Selection::Add:
1269 selection->add (touched);
1271 case Selection::Toggle:
1272 selection->add (touched);
1274 case Selection::Set:
1275 selection->set (touched);
1277 case Selection::Extend:
1278 /* meaningless, because we're selecting everything */
1281 commit_reversible_command ();
1285 Editor::invert_selection_in_track ()
1287 list<Selectable *> touched;
1289 if (!clicked_routeview) {
1293 clicked_routeview->get_inverted_selectables (*selection, touched);
1294 selection->set (touched);
1298 Editor::invert_selection ()
1300 list<Selectable *> touched;
1302 if (_internal_editing) {
1303 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1304 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1306 mrv->invert_selection ();
1312 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1313 if ((*iter)->hidden()) {
1316 (*iter)->get_inverted_selectables (*selection, touched);
1319 selection->set (touched);
1322 /** @param start Start time in session frames.
1323 * @param end End time in session frames.
1324 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
1325 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
1326 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
1327 * within the region are already selected.
1330 Editor::select_all_within (framepos_t start, framepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected)
1332 list<Selectable*> found;
1334 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1336 if ((*iter)->hidden()) {
1340 (*iter)->get_selectables (start, end, top, bot, found);
1343 if (found.empty()) {
1347 if (preserve_if_selected && op != Selection::Toggle) {
1348 list<Selectable*>::iterator i = found.begin();
1349 while (i != found.end() && (*i)->get_selected()) {
1353 if (i == found.end()) {
1358 begin_reversible_command (_("select all within"));
1360 case Selection::Add:
1361 selection->add (found);
1363 case Selection::Toggle:
1364 selection->toggle (found);
1366 case Selection::Set:
1367 selection->set (found);
1369 case Selection::Extend:
1370 /* not defined yet */
1374 commit_reversible_command ();
1378 Editor::set_selection_from_region ()
1380 if (selection->regions.empty()) {
1384 selection->set (selection->regions.start(), selection->regions.end_frame());
1385 if (!Profile->get_sae()) {
1386 set_mouse_mode (Editing::MouseRange, false);
1391 Editor::set_selection_from_punch()
1395 if ((location = _session->locations()->auto_punch_location()) == 0) {
1399 set_selection_from_range (*location);
1403 Editor::set_selection_from_loop()
1407 if ((location = _session->locations()->auto_loop_location()) == 0) {
1410 set_selection_from_range (*location);
1414 Editor::set_selection_from_range (Location& loc)
1416 begin_reversible_command (_("set selection from range"));
1417 selection->set (loc.start(), loc.end());
1418 commit_reversible_command ();
1420 if (!Profile->get_sae()) {
1421 set_mouse_mode (Editing::MouseRange, false);
1426 Editor::select_all_selectables_using_time_selection ()
1428 list<Selectable *> touched;
1430 if (selection->time.empty()) {
1434 framepos_t start = selection->time[clicked_selection].start;
1435 framepos_t end = selection->time[clicked_selection].end;
1437 if (end - start < 1) {
1443 if (selection->tracks.empty()) {
1446 ts = &selection->tracks;
1449 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1450 if ((*iter)->hidden()) {
1453 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1456 begin_reversible_command (_("select all from range"));
1457 selection->set (touched);
1458 commit_reversible_command ();
1463 Editor::select_all_selectables_using_punch()
1465 Location* location = _session->locations()->auto_punch_location();
1466 list<Selectable *> touched;
1468 if (location == 0 || (location->end() - location->start() <= 1)) {
1475 if (selection->tracks.empty()) {
1478 ts = &selection->tracks;
1481 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1482 if ((*iter)->hidden()) {
1485 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1487 begin_reversible_command (_("select all from punch"));
1488 selection->set (touched);
1489 commit_reversible_command ();
1494 Editor::select_all_selectables_using_loop()
1496 Location* location = _session->locations()->auto_loop_location();
1497 list<Selectable *> touched;
1499 if (location == 0 || (location->end() - location->start() <= 1)) {
1506 if (selection->tracks.empty()) {
1509 ts = &selection->tracks;
1512 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1513 if ((*iter)->hidden()) {
1516 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1518 begin_reversible_command (_("select all from loop"));
1519 selection->set (touched);
1520 commit_reversible_command ();
1525 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1529 list<Selectable *> touched;
1532 start = cursor->current_frame;
1533 end = _session->current_end_frame();
1535 if (cursor->current_frame > 0) {
1537 end = cursor->current_frame - 1;
1543 if (_internal_editing) {
1544 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1545 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1547 mrv->select_range (start, end);
1554 begin_reversible_command (_("select all after cursor"));
1556 begin_reversible_command (_("select all before cursor"));
1561 if (selection->tracks.empty()) {
1564 ts = &selection->tracks;
1567 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1568 if ((*iter)->hidden()) {
1571 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1573 selection->set (touched);
1574 commit_reversible_command ();
1578 Editor::select_all_selectables_using_edit (bool after)
1582 list<Selectable *> touched;
1585 start = get_preferred_edit_position();
1586 end = _session->current_end_frame();
1588 if ((end = get_preferred_edit_position()) > 1) {
1596 if (_internal_editing) {
1597 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1598 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1599 mrv->select_range (start, end);
1605 begin_reversible_command (_("select all after edit"));
1607 begin_reversible_command (_("select all before edit"));
1612 if (selection->tracks.empty()) {
1615 ts = &selection->tracks;
1618 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1619 if ((*iter)->hidden()) {
1622 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1624 selection->set (touched);
1625 commit_reversible_command ();
1629 Editor::select_all_selectables_between (bool /*within*/)
1633 list<Selectable *> touched;
1635 if (!get_edit_op_range (start, end)) {
1639 if (_internal_editing) {
1640 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1641 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1642 mrv->select_range (start, end);
1649 if (selection->tracks.empty()) {
1652 ts = &selection->tracks;
1655 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1656 if ((*iter)->hidden()) {
1659 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1662 selection->set (touched);
1666 Editor::select_range_between ()
1671 if (mouse_mode == MouseRange && !selection->time.empty()) {
1672 selection->clear_time ();
1675 if (!get_edit_op_range (start, end)) {
1679 set_mouse_mode (MouseRange);
1680 selection->set (start, end);
1684 Editor::get_edit_op_range (framepos_t& start, framepos_t& end) const
1689 /* in range mode, use any existing selection */
1691 if (mouse_mode == MouseRange && !selection->time.empty()) {
1692 /* we know that these are ordered */
1693 start = selection->time.start();
1694 end = selection->time.end_frame();
1698 if (!mouse_frame (m, ignored)) {
1699 /* mouse is not in a canvas, try playhead+selected marker.
1700 this is probably most true when using menus.
1703 if (selection->markers.empty()) {
1707 start = selection->markers.front()->position();
1708 end = _session->audible_frame();
1712 switch (_edit_point) {
1713 case EditAtPlayhead:
1714 if (selection->markers.empty()) {
1715 /* use mouse + playhead */
1717 end = _session->audible_frame();
1719 /* use playhead + selected marker */
1720 start = _session->audible_frame();
1721 end = selection->markers.front()->position();
1726 /* use mouse + selected marker */
1727 if (selection->markers.empty()) {
1729 end = _session->audible_frame();
1731 start = selection->markers.front()->position();
1736 case EditAtSelectedMarker:
1737 /* use mouse + selected marker */
1738 if (selection->markers.empty()) {
1740 MessageDialog win (_("No edit range defined"),
1745 win.set_secondary_text (
1746 _("the edit point is Selected Marker\nbut there is no selected marker."));
1749 win.set_default_response (RESPONSE_CLOSE);
1750 win.set_position (Gtk::WIN_POS_MOUSE);
1755 return false; // NO RANGE
1757 start = selection->markers.front()->position();
1771 /* turn range into one delimited by start...end,
1781 Editor::deselect_all ()
1783 selection->clear ();
1787 Editor::select_range_around_region (RegionView* rv)
1791 selection->set (&rv->get_time_axis_view());
1793 selection->time.clear ();
1794 boost::shared_ptr<Region> r = rv->region ();
1795 return selection->set (r->position(), r->position() + r->length());