2 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
3 * Copyright (C) 2007-2015 David Robillard <d@drobilla.net>
4 * Copyright (C) 2007-2018 Paul Davis <paul@linuxaudiosystems.com>
5 * Copyright (C) 2013-2017 Nick Mainsbridge <mainsbridge@gmail.com>
6 * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
7 * Copyright (C) 2014-2019 Ben Loftis <ben@harrisonconsoles.com>
8 * Copyright (C) 2015 André Nusser <andre.nusser@googlemail.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include "pbd/stacktrace.h"
29 #include "pbd/unwind.h"
31 #include "ardour/control_protocol_manager.h"
32 #include "ardour/midi_region.h"
33 #include "ardour/playlist.h"
34 #include "ardour/profile.h"
35 #include "ardour/route_group.h"
36 #include "ardour/selection.h"
37 #include "ardour/session.h"
38 #include "ardour/vca.h"
41 #include "editor_drag.h"
42 #include "editor_routes.h"
43 #include "editor_sources.h"
45 #include "audio_time_axis.h"
46 #include "audio_region_view.h"
47 #include "audio_streamview.h"
48 #include "automation_line.h"
49 #include "control_point.h"
50 #include "editor_regions.h"
51 #include "editor_cursors.h"
52 #include "midi_region_view.h"
58 using namespace ARDOUR;
62 using namespace Gtkmm2ext;
63 using namespace Editing;
65 struct TrackViewByPositionSorter
67 bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
68 return a->y_position() < b->y_position();
73 Editor::extend_selection_to_track (TimeAxisView& view)
75 if (selection->selected (&view)) {
76 /* already selected, do nothing */
80 if (selection->tracks.empty()) {
82 if (!selection->selected (&view)) {
83 selection->set (&view);
90 /* something is already selected, so figure out which range of things to add */
92 TrackViewList to_be_added;
93 TrackViewList sorted = track_views;
94 TrackViewByPositionSorter cmp;
95 bool passed_clicked = false;
100 /* figure out if we should go forward or backwards */
102 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
105 passed_clicked = true;
108 if (selection->selected (*i)) {
109 if (passed_clicked) {
118 passed_clicked = false;
122 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
125 passed_clicked = true;
129 if (passed_clicked) {
130 if ((*i)->hidden()) {
133 if (selection->selected (*i)) {
135 } else if (!(*i)->hidden()) {
136 to_be_added.push_back (*i);
143 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
146 passed_clicked = true;
150 if (passed_clicked) {
152 if ((*r)->hidden()) {
156 if (selection->selected (*r)) {
158 } else if (!(*r)->hidden()) {
159 to_be_added.push_back (*r);
165 if (!selection->selected (&view)) {
166 to_be_added.push_back (&view);
169 if (!to_be_added.empty()) {
170 selection->add (to_be_added);
178 Editor::select_all_tracks ()
180 TrackViewList visible_views;
181 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
182 if ((*i)->marked_for_display()) {
183 visible_views.push_back (*i);
186 PBD::Unwinder<bool> uw (_track_selection_change_without_scroll, true);
187 selection->set (visible_views);
190 /** Select clicked_axisview, unless there are no currently selected
191 * tracks, in which case nothing will happen unless `force' is true.
194 Editor::set_selected_track_as_side_effect (Selection::Operation op)
196 if (!clicked_axisview) {
200 PBD::Unwinder<bool> uw (_editor_track_selection_change_without_scroll, true);
202 RouteGroup* group = NULL;
203 if (clicked_routeview) {
204 group = clicked_routeview->route()->route_group();
208 case Selection::Toggle:
209 if (selection->selected (clicked_axisview)) {
210 if (group && group->is_active()) {
211 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
212 if ((*i)->route_group() == group) {
213 selection->remove(*i);
217 selection->remove (clicked_axisview);
220 if (group && group->is_active()) {
221 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
222 if ((*i)->route_group() == group) {
227 selection->add (clicked_axisview);
233 if (group && group->is_active()) {
234 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
235 if ((*i)->route_group() == group) {
240 selection->add (clicked_axisview);
246 if (group && group->is_active()) {
247 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
248 if ((*i)->route_group() == group) {
253 selection->set (clicked_axisview);
257 case Selection::Extend:
264 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
266 begin_reversible_selection_op (X_("Set Selected Track"));
269 case Selection::Toggle:
270 if (selection->selected (&view)) {
272 selection->remove (&view);
275 selection->add (&view);
280 selection->add (&view);
284 selection->set (&view);
287 case Selection::Extend:
288 extend_selection_to_track (view);
292 commit_reversible_selection_op ();
296 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
298 if (!clicked_routeview) {
306 set_selected_track (*clicked_routeview, op, no_remove);
310 Editor::set_selected_control_point_from_click (bool press, Selection::Operation op)
312 if (!clicked_control_point) {
320 if (!selection->selected (clicked_control_point)) {
321 selection->set (clicked_control_point);
324 /* clicked on an already selected point */
328 if (selection->points.size() > 1) {
329 selection->set (clicked_control_point);
338 selection->add (clicked_control_point);
342 case Selection::Toggle:
344 /* This is a bit of a hack; if we Primary-Click-Drag a control
345 point (for push drag) we want the point we clicked on to be
346 selected, otherwise we end up confusingly dragging an
347 unselected point. So here we ensure that the point is selected
348 after the press, and if we subsequently get a release (meaning no
349 drag occurred) we set things up so that the toggle has happened.
351 if (press && !selection->selected (clicked_control_point)) {
352 /* This is the button press, and the control point is not selected; make it so,
353 in case this press leads to a drag. Also note that having done this, we don't
354 need to toggle again on release.
356 selection->toggle (clicked_control_point);
357 _control_point_toggled_on_press = true;
359 } else if (!press && !_control_point_toggled_on_press) {
360 /* This is the release, and the point wasn't toggled on the press, so do it now */
361 selection->toggle (clicked_control_point);
365 _control_point_toggled_on_press = false;
368 case Selection::Extend:
377 Editor::get_onscreen_tracks (TrackViewList& tvl)
379 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
380 if ((*i)->y_position() < _visible_canvas_height) {
386 /** Call a slot for a given `basis' track and also for any track that is in the same
387 * active route group with a particular set of properties.
389 * @param sl Slot to call.
390 * @param basis Basis track.
391 * @param prop Properties that active edit groups must share to be included in the map.
395 Editor::mapover_tracks (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
397 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
399 if (route_basis == 0) {
403 set<RouteTimeAxisView*> tracks;
404 tracks.insert (route_basis);
406 RouteGroup* group = route_basis->route()->route_group();
408 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id)) {
410 /* the basis is a member of an active route group, with the appropriate
411 properties; find other members */
413 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
414 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
415 if (v && v->route()->route_group() == group) {
422 uint32_t const sz = tracks.size ();
424 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
429 /** Call a slot for a given `basis' track and also for any track that is in the same
430 * active route group with a particular set of properties.
432 * @param sl Slot to call.
433 * @param basis Basis track.
434 * @param prop Properties that active edit groups must share to be included in the map.
438 Editor::mapover_tracks_with_unique_playlists (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
440 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
441 set<boost::shared_ptr<Playlist> > playlists;
443 if (route_basis == 0) {
447 set<RouteTimeAxisView*> tracks;
448 tracks.insert (route_basis);
450 RouteGroup* group = route_basis->route()->route_group(); // could be null, not a problem
452 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id)) {
454 /* the basis is a member of an active route group, with the appropriate
455 properties; find other members */
457 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
458 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
460 if (v && v->route()->route_group() == group) {
462 boost::shared_ptr<Track> t = v->track();
464 if (playlists.insert (t->playlist()).second) {
465 /* haven't seen this playlist yet */
469 /* not actually a "Track", but a timeaxis view that
470 we should mapover anyway.
479 uint32_t const sz = tracks.size ();
481 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
487 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
489 boost::shared_ptr<Playlist> pl;
490 vector<boost::shared_ptr<Region> > results;
492 boost::shared_ptr<Track> tr;
494 if ((tr = tv.track()) == 0) {
499 if (&tv == &basis->get_time_axis_view()) {
500 /* looking in same track as the original */
504 if ((pl = tr->playlist()) != 0) {
505 pl->get_equivalent_regions (basis->region(), results);
508 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
509 if ((marv = tv.view()->find_view (*ir)) != 0) {
510 all_equivs->push_back (marv);
516 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, PBD::PropertyID property) const
518 mapover_tracks_with_unique_playlists (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_time_axis_view(), property);
520 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
522 equivalent_regions.push_back (basis);
526 Editor::get_equivalent_regions (RegionSelection & basis, PBD::PropertyID prop) const
528 RegionSelection equivalent;
530 for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
532 vector<RegionView*> eq;
534 mapover_tracks_with_unique_playlists (
535 sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
536 &(*i)->get_time_axis_view(), prop);
538 for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
549 Editor::get_regionview_count_from_region_list (boost::shared_ptr<Region> region)
551 int region_count = 0;
553 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
555 RouteTimeAxisView* tatv;
557 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
559 boost::shared_ptr<Playlist> pl;
560 vector<boost::shared_ptr<Region> > results;
562 boost::shared_ptr<Track> tr;
564 if ((tr = tatv->track()) == 0) {
569 if ((pl = (tr->playlist())) != 0) {
570 pl->get_region_list_equivalent_regions (region, results);
573 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
574 if ((marv = tatv->view()->find_view (*ir)) != 0) {
587 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op)
589 vector<RegionView*> all_equivalent_regions;
592 if (!clicked_regionview || !clicked_routeview) {
597 button_release_can_deselect = false;
600 if (op == Selection::Toggle || op == Selection::Set) {
603 case Selection::Toggle:
604 if (selection->selected (clicked_regionview)) {
607 /* whatever was clicked was selected already; do nothing here but allow
608 the button release to deselect it
611 button_release_can_deselect = true;
614 if (button_release_can_deselect) {
616 /* just remove this one region, but only on a permitted button release */
618 selection->remove (clicked_regionview);
621 /* no more deselect action on button release till a new press
622 finds an already selected object.
625 button_release_can_deselect = false;
633 if (selection->selected (clicked_routeview)) {
634 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
636 all_equivalent_regions.push_back (clicked_regionview);
639 /* add all the equivalent regions, but only on button press */
641 if (!all_equivalent_regions.empty()) {
645 selection->add (all_equivalent_regions);
651 if (!selection->selected (clicked_regionview)) {
652 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
653 selection->set (all_equivalent_regions);
656 /* clicked on an already selected region */
660 if (selection->regions.size() > 1) {
661 /* collapse region selection down to just this one region (and its equivalents) */
662 get_equivalent_regions(clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
663 selection->set(all_equivalent_regions);
675 } else if (op == Selection::Extend) {
677 list<Selectable*> results;
678 samplepos_t last_sample;
679 samplepos_t first_sample;
680 bool same_track = false;
682 /* 1. find the last selected regionview in the track that was clicked in */
685 first_sample = max_samplepos;
687 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
688 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
690 if ((*x)->region()->last_sample() > last_sample) {
691 last_sample = (*x)->region()->last_sample();
694 if ((*x)->region()->first_sample() < first_sample) {
695 first_sample = (*x)->region()->first_sample();
704 /* 2. figure out the boundaries for our search for new objects */
706 switch (clicked_regionview->region()->coverage (first_sample, last_sample)) {
707 case Evoral::OverlapNone:
708 if (last_sample < clicked_regionview->region()->first_sample()) {
709 first_sample = last_sample;
710 last_sample = clicked_regionview->region()->last_sample();
712 last_sample = first_sample;
713 first_sample = clicked_regionview->region()->first_sample();
717 case Evoral::OverlapExternal:
718 if (last_sample < clicked_regionview->region()->first_sample()) {
719 first_sample = last_sample;
720 last_sample = clicked_regionview->region()->last_sample();
722 last_sample = first_sample;
723 first_sample = clicked_regionview->region()->first_sample();
727 case Evoral::OverlapInternal:
728 if (last_sample < clicked_regionview->region()->first_sample()) {
729 first_sample = last_sample;
730 last_sample = clicked_regionview->region()->last_sample();
732 last_sample = first_sample;
733 first_sample = clicked_regionview->region()->first_sample();
737 case Evoral::OverlapStart:
738 case Evoral::OverlapEnd:
739 /* nothing to do except add clicked region to selection, since it
740 overlaps with the existing selection in this track.
747 /* click in a track that has no regions selected, so extend vertically
748 to pick out all regions that are defined by the existing selection
753 first_sample = clicked_regionview->region()->position();
754 last_sample = clicked_regionview->region()->last_sample();
756 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
757 if ((*i)->region()->position() < first_sample) {
758 first_sample = (*i)->region()->position();
760 if ((*i)->region()->last_sample() + 1 > last_sample) {
761 last_sample = (*i)->region()->last_sample();
766 /* 2. find all the tracks we should select in */
768 set<RouteTimeAxisView*> relevant_tracks;
770 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
771 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
773 relevant_tracks.insert (r);
777 set<RouteTimeAxisView*> already_in_selection;
779 if (relevant_tracks.empty()) {
781 /* no tracks selected .. thus .. if the
782 regionview we're in isn't selected
783 (i.e. we're about to extend to it), then
784 find all tracks between the this one and
788 if (!selection->selected (clicked_regionview)) {
790 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&clicked_regionview->get_time_axis_view());
794 /* add this track to the ones we will search */
796 relevant_tracks.insert (rtv);
798 /* find the track closest to this one that
799 already a selected region.
802 RouteTimeAxisView* closest = 0;
803 int distance = INT_MAX;
804 int key = rtv->route()->presentation_info().order ();
806 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
808 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
810 if (artv && artv != rtv) {
812 pair<set<RouteTimeAxisView*>::iterator,bool> result;
814 result = already_in_selection.insert (artv);
817 /* newly added to already_in_selection */
819 int d = artv->route()->presentation_info().order ();
823 if (abs (d) < distance) {
833 /* now add all tracks between that one and this one */
835 int okey = closest->route()->presentation_info().order ();
841 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
842 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
843 if (artv && artv != rtv) {
845 int k = artv->route()->presentation_info().order ();
847 if (k >= okey && k <= key) {
849 /* in range but don't add it if
850 it already has tracks selected.
851 this avoids odd selection
852 behaviour that feels wrong.
855 if (find (already_in_selection.begin(),
856 already_in_selection.end(),
857 artv) == already_in_selection.end()) {
859 relevant_tracks.insert (artv);
869 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
870 one that was clicked.
873 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
874 (*t)->get_selectables (first_sample, last_sample, -1.0, -1.0, results);
877 /* 4. convert to a vector of regions */
879 vector<RegionView*> regions;
881 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
884 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
885 regions.push_back (arv);
889 if (!regions.empty()) {
890 selection->add (regions);
892 } else if (selection->regions.empty() && !selection->selected (clicked_regionview)) {
893 /* ensure that at least the clicked regionview is selected. */
894 selection->set (clicked_regionview);
905 Editor::set_selection (std::list<Selectable*> s, Selection::Operation op)
910 begin_reversible_selection_op (X_("set selection"));
912 case Selection::Toggle:
913 selection->toggle (s);
918 case Selection::Extend:
926 commit_reversible_selection_op () ;
930 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
932 vector<RegionView*> all_equivalent_regions;
934 get_regions_corresponding_to (region, all_equivalent_regions, region->whole_file());
936 if (all_equivalent_regions.empty()) {
940 begin_reversible_selection_op (X_("set selected regions"));
943 case Selection::Toggle:
944 /* XXX this is not correct */
945 selection->toggle (all_equivalent_regions);
948 selection->set (all_equivalent_regions);
950 case Selection::Extend:
951 selection->add (all_equivalent_regions);
954 selection->add (all_equivalent_regions);
958 commit_reversible_selection_op () ;
962 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
965 boost::shared_ptr<Region> r (weak_r.lock());
971 if ((rv = sv->find_view (r)) == 0) {
975 /* don't reset the selection if its something other than
976 a single other region.
979 if (selection->regions.size() > 1) {
983 begin_reversible_selection_op (X_("set selected regions"));
987 commit_reversible_selection_op () ;
993 Editor::presentation_info_changed (PropertyChange const & what_changed)
995 uint32_t n_tracks = 0;
996 uint32_t n_busses = 0;
998 uint32_t n_routes = 0;
999 uint32_t n_stripables = 0;
1001 /* We cannot ensure ordering of the handlers for
1002 * PresentationInfo::Changed, so we have to do everything in order
1003 * here, as a single handler.
1006 if (what_changed.contains (Properties::selected)) {
1007 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1008 (*i)->set_selected (false);
1009 (*i)->hide_selection ();
1013 /* STEP 1: set the GUI selection state (in which TimeAxisViews for the
1014 * currently selected stripable/controllable duples are found and added
1017 selection->core_selection_changed (what_changed);
1019 /* STEP 2: update TimeAxisView's knowledge of their selected state
1022 if (what_changed.contains (Properties::selected)) {
1024 StripableNotificationListPtr stripables (new StripableNotificationList);
1026 switch (selection->tracks.size()) {
1030 set_selected_mixer_strip (*(selection->tracks.back()));
1031 if (!_track_selection_change_without_scroll && !_editor_track_selection_change_without_scroll) {
1032 ensure_time_axis_view_is_visible (*(selection->tracks.back()), false);
1037 CoreSelection::StripableAutomationControls sc;
1038 _session->selection().get_stripables (sc);
1040 for (CoreSelection::StripableAutomationControls::const_iterator i = sc.begin(); i != sc.end(); ++i) {
1042 AxisView* av = axis_view_by_stripable ((*i).stripable);
1050 if (boost::dynamic_pointer_cast<Track> ((*i).stripable)) {
1053 } else if (boost::dynamic_pointer_cast<Route> ((*i).stripable)) {
1056 } else if (boost::dynamic_pointer_cast<VCA> ((*i).stripable)) {
1060 TimeAxisView* tav = dynamic_cast<TimeAxisView*> (av);
1064 continue; /* impossible */
1067 if (!(*i).controllable) {
1069 /* "parent" track selected */
1070 tav->set_selected (true);
1071 tav->reshow_selection (selection->time);
1075 /* possibly a child */
1077 TimeAxisView::Children c = tav->get_child_list ();
1079 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
1081 boost::shared_ptr<AutomationControl> control = (*j)->control ();
1083 if (control != (*i).controllable) {
1087 (*j)->set_selected (true);
1088 (*j)->reshow_selection (selection->time);
1092 stripables->push_back ((*i).stripable);
1095 ActionManager::set_sensitive (ActionManager::stripable_selection_sensitive_actions, (n_stripables > 0));
1096 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, (n_tracks > 0));
1097 ActionManager::set_sensitive (ActionManager::bus_selection_sensitive_actions, (n_busses > 0));
1098 ActionManager::set_sensitive (ActionManager::route_selection_sensitive_actions, (n_routes > 0));
1099 ActionManager::set_sensitive (ActionManager::vca_selection_sensitive_actions, (n_vcas > 0));
1101 sensitize_the_right_region_actions (false);
1103 /* STEP 4: notify control protocols */
1105 ControlProtocolManager::instance().stripable_selection_changed (stripables);
1107 if (sfbrowser && _session && !_session->deletion_in_progress()) {
1108 uint32_t audio_track_cnt = 0;
1109 uint32_t midi_track_cnt = 0;
1111 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
1112 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*x);
1115 if (atv->is_audio_track()) {
1120 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(*x);
1123 if (mtv->is_midi_track()) {
1130 sfbrowser->reset (audio_track_cnt, midi_track_cnt);
1134 /* STEP 4: update EditorRoutes treeview */
1138 soh.add (Properties::selected);
1139 soh.add (Properties::order);
1140 soh.add (Properties::hidden);
1142 if (what_changed.contains (soh)) {
1143 _routes->sync_treeview_from_presentation_info (what_changed);
1148 Editor::track_selection_changed ()
1150 /* reset paste count, so the plaste location doesn't get incremented
1151 * if we want to paste in the same place, but different track. */
1154 if ( _session->solo_selection_active() )
1155 play_solo_selection(false);
1159 Editor::time_selection_changed ()
1161 /* XXX this is superficially inefficient. Hide the selection in all
1162 * tracks, then show it in all selected tracks.
1164 * However, if you investigate what this actually does, it isn't
1165 * anywhere nearly as bad as it may appear. Remember: nothing is
1166 * redrawn or even recomputed during these two loops - that only
1167 * happens when we next render ...
1170 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1171 (*i)->hide_selection ();
1174 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1175 (*i)->show_selection (selection->time);
1178 if (selection->time.empty()) {
1179 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
1181 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
1184 /* propagate into backend, but only when there is no drag or we are at
1185 * the end of a drag, otherwise this is too expensive (could case a
1186 * locate per mouse motion event.
1189 if (_session && !_drags->active()) {
1190 if (selection->time.length() != 0) {
1191 _session->set_range_selection (selection->time.start(), selection->time.end_sample());
1193 _session->clear_range_selection ();
1198 /** Set all region actions to have a given sensitivity */
1200 Editor::sensitize_all_region_actions (bool s)
1202 Glib::ListHandle<Glib::RefPtr<Action> > all = _region_actions->get_actions ();
1204 for (Glib::ListHandle<Glib::RefPtr<Action> >::iterator i = all.begin(); i != all.end(); ++i) {
1205 (*i)->set_sensitive (s);
1208 _all_region_actions_sensitized = s;
1211 /** Sensitize region-based actions.
1213 * This method is called from whenever we leave the canvas, either by moving
1214 * the pointer out of it, or by popping up a context menu. See
1215 * Editor::{entered,left}_track_canvas() for details there.
1218 Editor::sensitize_the_right_region_actions (bool because_canvas_crossing)
1220 bool have_selection = false;
1221 bool have_entered = false;
1222 bool have_edit_point = false;
1223 bool have_selected_source = false;
1226 // std::cerr << "STRRA: crossing ? " << because_canvas_crossing << " within ? " << within_track_canvas
1229 if (!selection->regions.empty()) {
1230 have_selection = true;
1231 rs = selection->regions;
1234 if (entered_regionview) {
1235 have_entered = true;
1236 rs.add (entered_regionview);
1239 if ( _sources->get_single_selection() ) {
1240 have_selected_source = true;
1243 if (rs.empty() && !selection->tracks.empty()) {
1245 /* no selected regions, but some selected tracks.
1248 if (_edit_point == EditAtMouse) {
1249 if (!within_track_canvas) {
1250 /* pointer is not in canvas, so edit point is meaningless */
1251 have_edit_point = false;
1253 /* inside canvas. we don't know where the edit
1254 point will be when an action is invoked, but
1255 assume it could intersect with a region.
1257 have_edit_point = true;
1260 RegionSelection at_edit_point;
1261 samplepos_t const where = get_preferred_edit_position (Editing::EDIT_IGNORE_NONE, false, !within_track_canvas);
1262 get_regions_at (at_edit_point, where, selection->tracks);
1263 if (!at_edit_point.empty()) {
1264 have_edit_point = true;
1267 rs.insert (rs.end(), at_edit_point.begin(), at_edit_point.end());
1272 //std::cerr << "\tfinal have selection: " << have_selection
1273 // << " have entered " << have_entered
1274 // << " have edit point " << have_edit_point
1275 // << " EP = " << enum_2_string (_edit_point)
1278 typedef std::map<std::string,RegionAction> RegionActionMap;
1280 _ignore_region_action = true;
1282 for (RegionActionMap::iterator x = region_action_map.begin(); x != region_action_map.end(); ++x) {
1283 RegionActionTarget tgt = x->second.target;
1284 bool sensitive = false;
1286 if ((tgt & SelectedRegions) && have_selection) {
1288 } else if ((tgt & EnteredRegions) && have_entered) {
1290 } else if ((tgt & EditPointRegions) && have_edit_point) {
1292 } else if ((tgt & ListSelection) && have_selected_source ) {
1296 x->second.action->set_sensitive (sensitive);
1299 /* Look through the regions that are selected and make notes about what we have got */
1301 bool have_audio = false;
1302 bool have_multichannel_audio = false;
1303 bool have_midi = false;
1304 bool have_locked = false;
1305 bool have_unlocked = false;
1306 bool have_video_locked = false;
1307 bool have_video_unlocked = false;
1308 bool have_position_lock_style_audio = false;
1309 bool have_position_lock_style_music = false;
1310 bool have_muted = false;
1311 bool have_unmuted = false;
1312 bool have_opaque = false;
1313 bool have_non_opaque = false;
1314 bool have_not_at_natural_position = false;
1315 bool have_envelope_active = false;
1316 bool have_envelope_inactive = false;
1317 bool have_non_unity_scale_amplitude = false;
1318 bool have_compound_regions = false;
1319 bool have_inactive_fade_in = false;
1320 bool have_inactive_fade_out = false;
1321 bool have_active_fade_in = false;
1322 bool have_active_fade_out = false;
1323 bool have_transients = false;
1325 for (list<RegionView*>::const_iterator i = rs.begin(); i != rs.end(); ++i) {
1327 boost::shared_ptr<Region> r = (*i)->region ();
1328 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
1332 if (ar->n_channels() > 1) {
1333 have_multichannel_audio = true;
1337 if (boost::dynamic_pointer_cast<MidiRegion> (r)) {
1341 if (r->is_compound()) {
1342 have_compound_regions = true;
1348 have_unlocked = true;
1351 if (r->video_locked()) {
1352 have_video_locked = true;
1354 have_video_unlocked = true;
1357 if (r->position_lock_style() == MusicTime) {
1358 have_position_lock_style_music = true;
1360 have_position_lock_style_audio = true;
1366 have_unmuted = true;
1372 have_non_opaque = true;
1375 if (!r->at_natural_position()) {
1376 have_not_at_natural_position = true;
1379 if (r->has_transients ()){
1380 have_transients = true;
1384 if (ar->envelope_active()) {
1385 have_envelope_active = true;
1387 have_envelope_inactive = true;
1390 if (ar->scale_amplitude() != 1) {
1391 have_non_unity_scale_amplitude = true;
1394 if (ar->fade_in_active ()) {
1395 have_active_fade_in = true;
1397 have_inactive_fade_in = true;
1400 if (ar->fade_out_active ()) {
1401 have_active_fade_out = true;
1403 have_inactive_fade_out = true;
1408 _region_actions->get_action("split-region-at-transients")->set_sensitive (have_transients);
1410 if (rs.size() > 1) {
1411 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1412 _region_actions->get_action("show-region-properties")->set_sensitive (false);
1413 _region_actions->get_action("rename-region")->set_sensitive (false);
1415 /* XXX need to check whether there is than 1 per
1416 playlist, because otherwise this makes no sense.
1418 _region_actions->get_action("combine-regions")->set_sensitive (true);
1420 _region_actions->get_action("combine-regions")->set_sensitive (false);
1422 } else if (rs.size() == 1) {
1423 _region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
1424 _region_actions->get_action("close-region-gaps")->set_sensitive (false);
1425 _region_actions->get_action("combine-regions")->set_sensitive (false);
1428 if (!have_multichannel_audio) {
1429 _region_actions->get_action("split-multichannel-region")->set_sensitive (false);
1433 editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (false);
1434 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1435 _region_actions->get_action("quantize-region")->set_sensitive (false);
1436 _region_actions->get_action("legatize-region")->set_sensitive (false);
1437 _region_actions->get_action("remove-overlap")->set_sensitive (false);
1438 _region_actions->get_action("transform-region")->set_sensitive (false);
1439 _region_actions->get_action("fork-region")->set_sensitive (false);
1440 _region_actions->get_action("insert-patch-change-context")->set_sensitive (false);
1441 _region_actions->get_action("insert-patch-change")->set_sensitive (false);
1442 _region_actions->get_action("transpose-region")->set_sensitive (false);
1444 editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (true);
1445 /* others were already marked sensitive */
1448 /* ok, moving along... */
1450 if (have_compound_regions) {
1451 _region_actions->get_action("uncombine-regions")->set_sensitive (true);
1453 _region_actions->get_action("uncombine-regions")->set_sensitive (false);
1458 if (have_envelope_active && !have_envelope_inactive) {
1459 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active ();
1460 } else if (have_envelope_active && have_envelope_inactive) {
1461 // Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_inconsistent ();
1466 _region_actions->get_action("loudness-analyze-region")->set_sensitive (false);
1467 _region_actions->get_action("spectral-analyze-region")->set_sensitive (false);
1468 _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
1469 _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
1470 _region_actions->get_action("pitch-shift-region")->set_sensitive (false);
1471 _region_actions->get_action("strip-region-silence")->set_sensitive (false);
1472 _region_actions->get_action("show-rhythm-ferret")->set_sensitive (false);
1476 if (!have_non_unity_scale_amplitude || !have_audio) {
1477 _region_actions->get_action("reset-region-scale-amplitude")->set_sensitive (false);
1480 Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"));
1481 a->set_active (have_locked && !have_unlocked);
1482 if (have_locked && have_unlocked) {
1483 // a->set_inconsistent ();
1486 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-video-lock"));
1487 a->set_active (have_video_locked && !have_video_unlocked);
1488 if (have_video_locked && have_video_unlocked) {
1489 // a->set_inconsistent ();
1492 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
1493 a->set_active (have_position_lock_style_music && !have_position_lock_style_audio);
1495 vector<Widget*> proxies = a->get_proxies();
1496 for (vector<Widget*>::iterator p = proxies.begin(); p != proxies.end(); ++p) {
1497 Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (*p);
1499 cmi->set_inconsistent (have_position_lock_style_music && have_position_lock_style_audio);
1503 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"));
1504 a->set_active (have_muted && !have_unmuted);
1505 if (have_muted && have_unmuted) {
1506 // a->set_inconsistent ();
1509 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"));
1510 a->set_active (have_opaque && !have_non_opaque);
1511 if (have_opaque && have_non_opaque) {
1512 // a->set_inconsistent ();
1515 if (!have_not_at_natural_position) {
1516 _region_actions->get_action("naturalize-region")->set_sensitive (false);
1519 /* Todo: insert-region-from-source-list */
1520 /* XXX: should also check that there is a track of the appropriate type for the selected region */
1522 if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
1523 _region_actions->get_action("insert-region-from-source-list")->set_sensitive (false);
1525 _region_actions->get_action("insert-region-from-source-list")->set_sensitive (true);
1529 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-in"));
1530 a->set_active (have_active_fade_in && !have_inactive_fade_in);
1531 if (have_active_fade_in && have_inactive_fade_in) {
1532 // a->set_inconsistent ();
1535 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-out"));
1536 a->set_active (have_active_fade_out && !have_inactive_fade_out);
1538 if (have_active_fade_out && have_inactive_fade_out) {
1539 // a->set_inconsistent ();
1542 bool const have_active_fade = have_active_fade_in || have_active_fade_out;
1543 bool const have_inactive_fade = have_inactive_fade_in || have_inactive_fade_out;
1545 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fades"));
1546 a->set_active (have_active_fade && !have_inactive_fade);
1548 if (have_active_fade && have_inactive_fade) {
1549 // a->set_inconsistent ();
1552 _ignore_region_action = false;
1554 _all_region_actions_sensitized = false;
1558 Editor::region_selection_changed ()
1560 _regions->block_change_connection (true);
1561 editor_regions_selection_changed_connection.block(true);
1563 if (_region_selection_change_updates_region_list) {
1564 _regions->unselect_all ();
1567 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1568 (*i)->set_selected_regionviews (selection->regions);
1571 if (_region_selection_change_updates_region_list) {
1572 _regions->set_selected (selection->regions);
1575 _regions->block_change_connection (false);
1576 editor_regions_selection_changed_connection.block(false);
1578 sensitize_the_right_region_actions (false);
1580 /* propagate into backend */
1583 if (!selection->regions.empty()) {
1584 _session->set_object_selection (selection->regions.start(), selection->regions.end_sample());
1586 _session->clear_object_selection ();
1589 if (_session->solo_selection_active()) {
1590 play_solo_selection(false);
1593 /* set nudge button color */
1594 if (! get_regions_from_selection_and_entered().empty()) {
1596 nudge_forward_button.set_name ("nudge button");
1597 nudge_backward_button.set_name ("nudge button");
1599 /* nudge marker or playhead */
1600 nudge_forward_button.set_name ("transport button");
1601 nudge_backward_button.set_name ("transport button");
1604 //there are a few global Editor->Select actions which select regions even if you aren't in Object mode.
1605 //if regions are selected, we must always force the mouse mode to Object...
1606 //... otherwise the user is confusingly left with selected regions that can't be manipulated.
1607 if (!selection->regions.empty()) {
1608 set_mouse_mode( MouseObject, false );
1613 Editor::point_selection_changed ()
1615 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1616 (*i)->set_selected_points (selection->points);
1621 Editor::select_all_in_track (Selection::Operation op)
1623 list<Selectable *> touched;
1625 if (!clicked_routeview) {
1629 begin_reversible_selection_op (X_("Select All in Track"));
1631 clicked_routeview->get_selectables (0, max_samplepos, 0, DBL_MAX, touched);
1634 case Selection::Toggle:
1635 selection->add (touched);
1637 case Selection::Set:
1638 selection->set (touched);
1640 case Selection::Extend:
1641 /* meaningless, because we're selecting everything */
1643 case Selection::Add:
1644 selection->add (touched);
1648 commit_reversible_selection_op ();
1652 Editor::select_all_internal_edit (Selection::Operation)
1654 bool selected = false;
1656 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1657 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1659 mrv->select_all_notes ();
1664 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(entered_regionview);
1666 mrv->select_all_notes ();
1674 Editor::select_all_objects (Selection::Operation op)
1676 list<Selectable *> touched;
1678 if (internal_editing() && select_all_internal_edit(op)) {
1679 return; // Selected notes
1684 if (selection->tracks.empty()) {
1687 ts = selection->tracks;
1690 for (TrackViewList::iterator iter = ts.begin(); iter != ts.end(); ++iter) {
1691 if ((*iter)->hidden()) {
1694 (*iter)->get_selectables (0, max_samplepos, 0, DBL_MAX, touched);
1697 begin_reversible_selection_op (X_("select all"));
1699 case Selection::Add:
1700 selection->add (touched);
1702 case Selection::Toggle:
1703 selection->toggle (touched);
1705 case Selection::Set:
1706 selection->set (touched);
1708 case Selection::Extend:
1709 /* meaningless, because we're selecting everything */
1712 commit_reversible_selection_op ();
1716 Editor::invert_selection_in_track ()
1718 list<Selectable *> touched;
1720 if (!clicked_routeview) {
1724 begin_reversible_selection_op (X_("Invert Selection in Track"));
1725 clicked_routeview->get_inverted_selectables (*selection, touched);
1726 selection->set (touched);
1727 commit_reversible_selection_op ();
1731 Editor::invert_selection ()
1734 if (internal_editing()) {
1735 for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
1736 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1738 mrv->invert_selection ();
1744 if (!selection->tracks.empty()) {
1746 TrackViewList inverted;
1748 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1749 if (!(*iter)->selected()) {
1750 inverted.push_back (*iter);
1754 begin_reversible_selection_op (X_("Invert Track Selection"));
1755 selection->set (inverted);
1756 commit_reversible_selection_op ();
1760 list<Selectable *> touched;
1762 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1763 if ((*iter)->hidden()) {
1766 (*iter)->get_inverted_selectables (*selection, touched);
1769 begin_reversible_selection_op (X_("Invert ObjectSelection"));
1770 selection->set (touched);
1771 commit_reversible_selection_op ();
1775 /** @param start Start time in session samples.
1776 * @param end End time in session samples.
1777 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
1778 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
1779 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
1780 * within the region are already selected.
1783 Editor::select_all_within (samplepos_t start, samplepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected)
1785 list<Selectable*> found;
1787 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1789 if ((*iter)->hidden()) {
1793 (*iter)->get_selectables (start, end, top, bot, found);
1796 if (found.empty()) {
1797 selection->clear_objects();
1798 selection->clear_time ();
1802 if (preserve_if_selected && op != Selection::Toggle) {
1803 list<Selectable*>::iterator i = found.begin();
1804 while (i != found.end() && (*i)->selected()) {
1808 if (i == found.end()) {
1813 begin_reversible_selection_op (X_("select all within"));
1815 case Selection::Add:
1816 selection->add (found);
1818 case Selection::Toggle:
1819 selection->toggle (found);
1821 case Selection::Set:
1822 selection->set (found);
1824 case Selection::Extend:
1825 /* not defined yet */
1829 commit_reversible_selection_op ();
1833 Editor::set_selection_from_region ()
1835 if (selection->regions.empty()) {
1839 /* find all the tracks that have selected regions */
1841 set<TimeAxisView*> tracks;
1843 for (RegionSelection::const_iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
1844 tracks.insert (&(*r)->get_time_axis_view());
1848 tvl.insert (tvl.end(), tracks.begin(), tracks.end());
1850 /* select range (this will clear the region selection) */
1852 selection->set (selection->regions.start(), selection->regions.end_sample());
1854 /* and select the tracks */
1856 selection->set (tvl);
1858 if (!get_smart_mode () || !(mouse_mode == Editing::MouseObject) ) {
1859 set_mouse_mode (Editing::MouseRange, false);
1864 Editor::set_selection_from_punch()
1868 if ((location = _session->locations()->auto_punch_location()) == 0) {
1872 set_selection_from_range (*location);
1876 Editor::set_selection_from_loop()
1880 if ((location = _session->locations()->auto_loop_location()) == 0) {
1883 set_selection_from_range (*location);
1887 Editor::set_selection_from_range (Location& loc)
1889 begin_reversible_selection_op (X_("set selection from range"));
1891 selection->set (loc.start(), loc.end());
1893 // if no tracks are selected, enable all tracks
1894 // (_something_ has to be selected for any range selection, otherwise the user won't see anything)
1895 if (selection->tracks.empty()) {
1896 select_all_tracks();
1899 commit_reversible_selection_op ();
1901 if (!get_smart_mode () || mouse_mode != Editing::MouseObject) {
1902 set_mouse_mode (MouseRange, false);
1907 Editor::select_all_selectables_using_time_selection ()
1909 list<Selectable *> touched;
1911 if (selection->time.empty()) {
1915 samplepos_t start = selection->time[clicked_selection].start;
1916 samplepos_t end = selection->time[clicked_selection].end;
1918 if (end - start < 1) {
1924 if (selection->tracks.empty()) {
1927 ts = &selection->tracks;
1930 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1931 if ((*iter)->hidden()) {
1934 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1937 begin_reversible_selection_op (X_("select all from range"));
1938 selection->set (touched);
1939 commit_reversible_selection_op ();
1944 Editor::select_all_selectables_using_punch()
1946 Location* location = _session->locations()->auto_punch_location();
1947 list<Selectable *> touched;
1949 if (location == 0 || (location->end() - location->start() <= 1)) {
1956 if (selection->tracks.empty()) {
1959 ts = &selection->tracks;
1962 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1963 if ((*iter)->hidden()) {
1966 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1968 begin_reversible_selection_op (X_("select all from punch"));
1969 selection->set (touched);
1970 commit_reversible_selection_op ();
1975 Editor::select_all_selectables_using_loop()
1977 Location* location = _session->locations()->auto_loop_location();
1978 list<Selectable *> touched;
1980 if (location == 0 || (location->end() - location->start() <= 1)) {
1987 if (selection->tracks.empty()) {
1990 ts = &selection->tracks;
1993 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1994 if ((*iter)->hidden()) {
1997 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1999 begin_reversible_selection_op (X_("select all from loop"));
2000 selection->set (touched);
2001 commit_reversible_selection_op ();
2006 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
2010 list<Selectable *> touched;
2013 start = cursor->current_sample();
2014 end = _session->current_end_sample();
2016 if (cursor->current_sample() > 0) {
2018 end = cursor->current_sample() - 1;
2024 if (internal_editing()) {
2025 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2026 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
2028 mrv->select_range (start, end);
2035 begin_reversible_selection_op (X_("select all after cursor"));
2037 begin_reversible_selection_op (X_("select all before cursor"));
2042 if (selection->tracks.empty()) {
2045 ts = &selection->tracks;
2048 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
2049 if ((*iter)->hidden()) {
2052 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
2054 selection->set (touched);
2055 commit_reversible_selection_op ();
2059 Editor::select_all_selectables_using_edit (bool after, bool from_context_menu)
2063 list<Selectable *> touched;
2066 start = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu);
2067 end = _session->current_end_sample();
2069 if ((end = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu)) > 1) {
2077 if (internal_editing()) {
2078 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2079 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
2080 mrv->select_range (start, end);
2086 begin_reversible_selection_op (X_("select all after edit"));
2088 begin_reversible_selection_op (X_("select all before edit"));
2093 if (selection->tracks.empty()) {
2096 ts = &selection->tracks;
2099 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
2100 if ((*iter)->hidden()) {
2103 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
2105 selection->set (touched);
2106 commit_reversible_selection_op ();
2110 Editor::select_all_selectables_between (bool within)
2114 list<Selectable *> touched;
2116 if (!get_edit_op_range (start, end)) {
2120 if (internal_editing()) {
2121 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2122 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
2123 mrv->select_range (start, end);
2130 if (selection->tracks.empty()) {
2133 ts = &selection->tracks;
2136 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
2137 if ((*iter)->hidden()) {
2140 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched, within);
2143 begin_reversible_selection_op (X_("Select all Selectables Between"));
2144 selection->set (touched);
2145 commit_reversible_selection_op ();
2149 Editor::select_range_between ()
2154 if (!selection->time.empty()) {
2155 selection->clear_time ();
2158 if (!get_edit_op_range (start, end)) {
2162 if (!get_smart_mode () || mouse_mode != Editing::MouseObject) {
2163 set_mouse_mode (MouseRange, false);
2166 begin_reversible_selection_op (X_("Select Range Between"));
2167 selection->set (start, end);
2168 commit_reversible_selection_op ();
2172 Editor::get_edit_op_range (samplepos_t& start, samplepos_t& end) const
2174 /* if an explicit range exists, use it */
2176 if ((mouse_mode == MouseRange || get_smart_mode()) && !selection->time.empty()) {
2177 /* we know that these are ordered */
2178 start = selection->time.start();
2179 end = selection->time.end_sample();
2189 Editor::deselect_all ()
2191 begin_reversible_selection_op (X_("Deselect All"));
2192 selection->clear ();
2193 commit_reversible_selection_op ();
2197 Editor::select_range (samplepos_t s, samplepos_t e)
2199 begin_reversible_selection_op (X_("Select Range"));
2200 selection->add (clicked_axisview);
2201 selection->time.clear ();
2202 long ret = selection->set (s, e);
2203 commit_reversible_selection_op ();