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/diskstream.h"
26 #include "ardour/playlist.h"
27 #include "ardour/route_group.h"
28 #include "ardour/profile.h"
32 #include "audio_time_axis.h"
33 #include "audio_region_view.h"
34 #include "audio_streamview.h"
35 #include "automation_line.h"
36 #include "control_point.h"
37 #include "editor_regions.h"
43 using namespace ARDOUR;
47 using namespace Gtkmm2ext;
48 using namespace Editing;
50 struct TrackViewByPositionSorter
52 bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
53 return a->y_position() < b->y_position();
58 Editor::extend_selection_to_track (TimeAxisView& view)
60 if (selection->selected (&view)) {
61 /* already selected, do nothing */
65 if (selection->tracks.empty()) {
67 if (!selection->selected (&view)) {
68 selection->set (&view);
75 /* something is already selected, so figure out which range of things to add */
77 TrackViewList to_be_added;
78 TrackViewList sorted = track_views;
79 TrackViewByPositionSorter cmp;
80 bool passed_clicked = false;
85 if (!selection->selected (&view)) {
86 to_be_added.push_back (&view);
89 /* figure out if we should go forward or backwards */
91 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
94 passed_clicked = true;
97 if (selection->selected (*i)) {
107 passed_clicked = false;
111 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
114 passed_clicked = true;
118 if (passed_clicked) {
119 if ((*i)->hidden()) {
122 if (selection->selected (*i)) {
124 } else if (!(*i)->hidden()) {
125 to_be_added.push_back (*i);
132 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
135 passed_clicked = true;
139 if (passed_clicked) {
141 if ((*r)->hidden()) {
145 if (selection->selected (*r)) {
147 } else if (!(*r)->hidden()) {
148 to_be_added.push_back (*r);
154 if (!to_be_added.empty()) {
155 selection->add (to_be_added);
163 Editor::select_all_tracks ()
165 TrackViewList visible_views;
166 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
167 if ((*i)->marked_for_display()) {
168 visible_views.push_back (*i);
171 selection->set (visible_views);
175 Editor::set_selected_track_as_side_effect (bool force)
177 if (!clicked_routeview) {
181 if (!selection->tracks.empty()) {
182 if (!selection->selected (clicked_routeview)) {
183 selection->add (clicked_routeview);
187 selection->set (clicked_routeview);
192 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
195 case Selection::Toggle:
196 if (selection->selected (&view)) {
198 selection->remove (&view);
201 selection->add (&view);
206 if (!selection->selected (&view)) {
207 selection->add (&view);
212 selection->set (&view);
215 case Selection::Extend:
216 extend_selection_to_track (view);
222 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
224 if (!clicked_routeview) {
232 set_selected_track (*clicked_routeview, op, no_remove);
236 Editor::set_selected_control_point_from_click (Selection::Operation op, bool /*no_remove*/)
238 if (!clicked_control_point) {
242 /* select this point and any others that it represents */
247 x1 = pixel_to_frame (clicked_control_point->get_x() - 10);
248 x2 = pixel_to_frame (clicked_control_point->get_x() + 10);
249 y1 = clicked_control_point->get_x() - 10;
250 y2 = clicked_control_point->get_y() + 10;
252 return select_all_within (x1, x2, y1, y2, selection->tracks, op);
256 Editor::get_onscreen_tracks (TrackViewList& tvl)
258 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
259 if ((*i)->y_position() < _canvas_height) {
265 /** Given a track, find any other tracks that are in the same active route group with a given property.
266 * @param basis Base track.
267 * @param equivs Filled with the base track and the found tracks.
268 * @param prop Property to look for in route groups.
272 Editor::get_equivalent_tracks (RouteTimeAxisView* basis, set<RouteTimeAxisView*> & equivs, RouteGroup::Property prop) const
274 equivs.insert (basis);
276 RouteGroup* group = basis->route()->route_group();
277 if (group && group->active_property (prop)) {
279 /* the basis is a member of an active route group, with the appropriate
280 properties; find other members */
282 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
283 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
284 if (v && v->route()->route_group() == group) {
291 /** Find tracks that are selected, and also those that are in the same `selection'-enabled route
292 * group as one that is selected.
293 * @param relevant_tracks set to add tracks to.
297 Editor::get_relevant_tracks (set<RouteTimeAxisView*>& relevant_tracks) const
299 for (TrackSelection::iterator ti = selection->tracks.begin(); ti != selection->tracks.end(); ++ti) {
300 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*ti);
302 get_equivalent_tracks (rtv, relevant_tracks, RouteGroup::Select);
307 /** Call a slot for a given `basis' track and also for any track that is in the same
308 * active route group with a particular set of properties.
310 * @param sl Slot to call.
311 * @param basis Basis track.
312 * @param prop Properties that active edit groups must share to be included in the map.
316 Editor::mapover_tracks (slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, RouteGroup::Property prop) const
318 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
319 if (route_basis == 0) {
323 set<RouteTimeAxisView*> tracks;
324 get_equivalent_tracks (route_basis, tracks, prop);
327 uint32_t const sz = tracks.size ();
328 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
334 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
336 boost::shared_ptr<Playlist> pl;
337 vector<boost::shared_ptr<Region> > results;
339 boost::shared_ptr<Diskstream> ds;
341 if ((ds = tv.get_diskstream()) == 0) {
346 if (&tv == &basis->get_time_axis_view()) {
347 /* looking in same track as the original */
351 if ((pl = ds->playlist()) != 0) {
352 pl->get_equivalent_regions (basis->region(), results);
355 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
356 if ((marv = tv.view()->find_view (*ir)) != 0) {
357 all_equivs->push_back (marv);
363 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, RouteGroup::Property prop) const
365 mapover_tracks (bind (mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_trackview(), prop);
367 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
369 equivalent_regions.push_back (basis);
373 Editor::get_equivalent_regions (RegionSelection & basis, RouteGroup::Property prop) const
375 RegionSelection equivalent;
377 for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
379 vector<RegionView*> eq;
382 bind (mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
383 &(*i)->get_trackview(), prop
386 for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
398 Editor::get_regionview_count_from_region_list (boost::shared_ptr<Region> region)
400 int region_count = 0;
402 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
404 RouteTimeAxisView* tatv;
406 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
408 boost::shared_ptr<Playlist> pl;
409 vector<boost::shared_ptr<Region> > results;
411 boost::shared_ptr<Diskstream> ds;
413 if ((ds = tatv->get_diskstream()) == 0) {
418 if ((pl = (ds->playlist())) != 0) {
419 pl->get_region_list_equivalent_regions (region, results);
422 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
423 if ((marv = tatv->view()->find_view (*ir)) != 0) {
436 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool /*no_track_remove*/)
438 vector<RegionView*> all_equivalent_regions;
441 if (!clicked_regionview || !clicked_routeview) {
446 button_release_can_deselect = false;
449 if (op == Selection::Toggle || op == Selection::Set) {
453 case Selection::Toggle:
455 if (selection->selected (clicked_regionview)) {
458 /* whatever was clicked was selected already; do nothing here but allow
459 the button release to deselect it
462 button_release_can_deselect = true;
466 if (button_release_can_deselect) {
468 /* just remove this one region, but only on a permitted button release */
470 selection->remove (clicked_regionview);
473 /* no more deselect action on button release till a new press
474 finds an already selected object.
477 button_release_can_deselect = false;
485 if (selection->selected (clicked_routeview)) {
486 get_equivalent_regions (clicked_regionview, all_equivalent_regions, RouteGroup::Select);
488 all_equivalent_regions.push_back (clicked_regionview);
491 /* add all the equivalent regions, but only on button press */
495 if (!all_equivalent_regions.empty()) {
499 selection->add (all_equivalent_regions);
505 if (!selection->selected (clicked_regionview)) {
506 get_equivalent_regions (clicked_regionview, all_equivalent_regions, RouteGroup::Select);
507 selection->set (all_equivalent_regions);
510 /* no commit necessary: clicked on an already selected region */
520 } else if (op == Selection::Extend) {
522 list<Selectable*> results;
523 nframes64_t last_frame;
524 nframes64_t first_frame;
525 bool same_track = false;
527 /* 1. find the last selected regionview in the track that was clicked in */
530 first_frame = max_frames;
532 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
533 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
535 if ((*x)->region()->last_frame() > last_frame) {
536 last_frame = (*x)->region()->last_frame();
539 if ((*x)->region()->first_frame() < first_frame) {
540 first_frame = (*x)->region()->first_frame();
549 /* 2. figure out the boundaries for our search for new objects */
551 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
553 if (last_frame < clicked_regionview->region()->first_frame()) {
554 first_frame = last_frame;
555 last_frame = clicked_regionview->region()->last_frame();
557 last_frame = first_frame;
558 first_frame = clicked_regionview->region()->first_frame();
562 case OverlapExternal:
563 if (last_frame < clicked_regionview->region()->first_frame()) {
564 first_frame = last_frame;
565 last_frame = clicked_regionview->region()->last_frame();
567 last_frame = first_frame;
568 first_frame = clicked_regionview->region()->first_frame();
572 case OverlapInternal:
573 if (last_frame < clicked_regionview->region()->first_frame()) {
574 first_frame = last_frame;
575 last_frame = clicked_regionview->region()->last_frame();
577 last_frame = first_frame;
578 first_frame = clicked_regionview->region()->first_frame();
584 /* nothing to do except add clicked region to selection, since it
585 overlaps with the existing selection in this track.
592 /* click in a track that has no regions selected, so extend vertically
593 to pick out all regions that are defined by the existing selection
598 first_frame = entered_regionview->region()->position();
599 last_frame = entered_regionview->region()->last_frame();
601 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
602 if ((*i)->region()->position() < first_frame) {
603 first_frame = (*i)->region()->position();
605 if ((*i)->region()->last_frame() + 1 > last_frame) {
606 last_frame = (*i)->region()->last_frame();
611 /* 2. find all the tracks we should select in */
613 set<RouteTimeAxisView*> relevant_tracks;
614 set<RouteTimeAxisView*> already_in_selection;
616 get_relevant_tracks (relevant_tracks);
618 if (relevant_tracks.empty()) {
620 /* no relevant tracks -> no tracks selected .. thus .. if
621 the regionview we're in isn't selected (i.e. we're
622 about to extend to it), then find all tracks between
623 the this one and any selected ones.
626 if (!selection->selected (entered_regionview)) {
628 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&entered_regionview->get_time_axis_view());
632 /* add this track to the ones we will search */
634 relevant_tracks.insert (rtv);
636 /* find the track closest to this one that
637 already a selected region.
640 RouteTimeAxisView* closest = 0;
641 int distance = INT_MAX;
642 int key = rtv->route()->order_key ("editor");
644 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
646 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
648 if (artv && artv != rtv) {
650 pair<set<RouteTimeAxisView*>::iterator,bool> result;
652 result = already_in_selection.insert (artv);
655 /* newly added to already_in_selection */
658 int d = artv->route()->order_key ("editor");
662 if (abs (d) < distance) {
672 /* now add all tracks between that one and this one */
674 int okey = closest->route()->order_key ("editor");
680 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
681 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
682 if (artv && artv != rtv) {
684 int k = artv->route()->order_key ("editor");
686 if (k >= okey && k <= key) {
688 /* in range but don't add it if
689 it already has tracks selected.
690 this avoids odd selection
691 behaviour that feels wrong.
694 if (find (already_in_selection.begin(),
695 already_in_selection.end(),
696 artv) == already_in_selection.end()) {
698 relevant_tracks.insert (artv);
708 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
709 one that was clicked.
712 get_relevant_tracks (relevant_tracks);
714 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
715 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
718 /* 4. convert to a vector of regions */
720 vector<RegionView*> regions;
722 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
725 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
726 regions.push_back (arv);
730 if (!regions.empty()) {
731 selection->add (regions);
742 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
744 vector<RegionView*> all_equivalent_regions;
746 get_regions_corresponding_to (region, all_equivalent_regions);
748 if (all_equivalent_regions.empty()) {
752 begin_reversible_command (_("set selected regions"));
755 case Selection::Toggle:
756 /* XXX this is not correct */
757 selection->toggle (all_equivalent_regions);
760 selection->set (all_equivalent_regions);
762 case Selection::Extend:
763 selection->add (all_equivalent_regions);
766 selection->add (all_equivalent_regions);
770 commit_reversible_command () ;
774 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
777 boost::shared_ptr<Region> r (weak_r.lock());
783 if ((rv = sv->find_view (r)) == 0) {
787 /* don't reset the selection if its something other than
788 a single other region.
791 if (selection->regions.size() > 1) {
795 begin_reversible_command (_("set selected regions"));
799 commit_reversible_command () ;
805 Editor::track_selection_changed ()
807 switch (selection->tracks.size()){
811 set_selected_mixer_strip (*(selection->tracks.front()));
815 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
816 if (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end()) {
817 (*i)->set_selected (true);
819 (*i)->set_selected (false);
823 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
827 Editor::time_selection_changed ()
829 if (Profile->get_sae()) {
833 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
834 (*i)->hide_selection ();
837 if (selection->tracks.empty()) {
838 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
839 (*i)->show_selection (selection->time);
842 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
843 (*i)->show_selection (selection->time);
847 if (selection->time.empty()) {
848 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
850 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
856 Editor::sensitize_the_right_region_actions (bool have_selected_regions)
858 for (vector<Glib::RefPtr<Action> >::iterator x = ActionManager::region_selection_sensitive_actions.begin();
859 x != ActionManager::region_selection_sensitive_actions.end(); ++x) {
861 string accel_path = (*x)->get_accel_path ();
864 /* if there is an accelerator, it should always be sensitive
865 to allow for keyboard ops on entered regions.
868 bool known = ActionManager::lookup_entry (accel_path, key);
870 if (known && ((key.get_key() != GDK_VoidSymbol) && (key.get_key() != 0))) {
871 (*x)->set_sensitive (true);
873 (*x)->set_sensitive (have_selected_regions);
880 Editor::region_selection_changed ()
882 _regions->block_change_connection (true);
883 editor_regions_selection_changed_connection.block(true);
885 _regions->unselect_all ();
887 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
889 (*i)->set_selected_regionviews (selection->regions);
890 _regions->set_selected (selection->regions);
894 sensitize_the_right_region_actions (!selection->regions.empty());
896 _regions->block_change_connection (false);
897 editor_regions_selection_changed_connection.block(false);
901 Editor::point_selection_changed ()
903 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
904 (*i)->set_selected_points (selection->points);
909 Editor::select_all_in_track (Selection::Operation op)
911 list<Selectable *> touched;
913 if (!clicked_routeview) {
917 clicked_routeview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
920 case Selection::Toggle:
921 selection->add (touched);
924 selection->set (touched);
926 case Selection::Extend:
927 /* meaningless, because we're selecting everything */
930 selection->add (touched);
936 Editor::select_all (Selection::Operation op)
938 list<Selectable *> touched;
940 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
941 if ((*iter)->hidden()) {
944 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
946 begin_reversible_command (_("select all"));
949 selection->add (touched);
951 case Selection::Toggle:
952 selection->add (touched);
955 selection->set (touched);
957 case Selection::Extend:
958 /* meaningless, because we're selecting everything */
961 commit_reversible_command ();
964 Editor::invert_selection_in_track ()
966 list<Selectable *> touched;
968 if (!clicked_routeview) {
972 clicked_routeview->get_inverted_selectables (*selection, touched);
973 selection->set (touched);
977 Editor::invert_selection ()
979 list<Selectable *> touched;
981 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
982 if ((*iter)->hidden()) {
985 (*iter)->get_inverted_selectables (*selection, touched);
988 selection->set (touched);
992 Editor::select_all_within (nframes64_t start, nframes64_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op)
994 list<Selectable*> touched;
995 list<Selectable*>::size_type n = 0;
996 TrackViewList touched_tracks;
998 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
999 if ((*iter)->hidden()) {
1005 (*iter)->get_selectables (start, end, top, bot, touched);
1007 if (n != touched.size()) {
1008 touched_tracks.push_back (*iter);
1012 if (touched.empty()) {
1016 if (!touched_tracks.empty()) {
1019 case Selection::Add:
1020 selection->add (touched_tracks);
1022 case Selection::Toggle:
1023 selection->toggle (touched_tracks);
1025 case Selection::Set:
1026 selection->set (touched_tracks);
1028 case Selection::Extend:
1029 /* not defined yet */
1034 begin_reversible_command (_("select all within"));
1036 case Selection::Add:
1037 selection->add (touched);
1039 case Selection::Toggle:
1040 selection->toggle (touched);
1042 case Selection::Set:
1043 selection->set (touched);
1045 case Selection::Extend:
1046 /* not defined yet */
1050 commit_reversible_command ();
1052 return !touched.empty();
1056 Editor::set_selection_from_region ()
1058 if (selection->regions.empty()) {
1062 selection->set (0, selection->regions.start(), selection->regions.end_frame());
1063 if (!Profile->get_sae()) {
1064 set_mouse_mode (Editing::MouseRange, false);
1069 Editor::set_selection_from_punch()
1073 if ((location = session->locations()->auto_punch_location()) == 0) {
1077 set_selection_from_range (*location);
1081 Editor::set_selection_from_loop()
1085 if ((location = session->locations()->auto_loop_location()) == 0) {
1088 set_selection_from_range (*location);
1092 Editor::set_selection_from_range (Location& loc)
1094 begin_reversible_command (_("set selection from range"));
1095 selection->set (0, loc.start(), loc.end());
1096 commit_reversible_command ();
1098 if (!Profile->get_sae()) {
1099 set_mouse_mode (Editing::MouseRange, false);
1104 Editor::select_all_selectables_using_time_selection ()
1106 list<Selectable *> touched;
1108 if (selection->time.empty()) {
1112 nframes64_t start = selection->time[clicked_selection].start;
1113 nframes64_t end = selection->time[clicked_selection].end;
1115 if (end - start < 1) {
1121 if (selection->tracks.empty()) {
1124 ts = &selection->tracks;
1127 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1128 if ((*iter)->hidden()) {
1131 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1134 begin_reversible_command (_("select all from range"));
1135 selection->set (touched);
1136 commit_reversible_command ();
1141 Editor::select_all_selectables_using_punch()
1143 Location* location = session->locations()->auto_punch_location();
1144 list<Selectable *> touched;
1146 if (location == 0 || (location->end() - location->start() <= 1)) {
1153 if (selection->tracks.empty()) {
1156 ts = &selection->tracks;
1159 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1160 if ((*iter)->hidden()) {
1163 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1165 begin_reversible_command (_("select all from punch"));
1166 selection->set (touched);
1167 commit_reversible_command ();
1172 Editor::select_all_selectables_using_loop()
1174 Location* location = session->locations()->auto_loop_location();
1175 list<Selectable *> touched;
1177 if (location == 0 || (location->end() - location->start() <= 1)) {
1184 if (selection->tracks.empty()) {
1187 ts = &selection->tracks;
1190 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1191 if ((*iter)->hidden()) {
1194 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1196 begin_reversible_command (_("select all from loop"));
1197 selection->set (touched);
1198 commit_reversible_command ();
1203 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1207 list<Selectable *> touched;
1210 begin_reversible_command (_("select all after cursor"));
1211 start = cursor->current_frame ;
1212 end = session->current_end_frame();
1214 if (cursor->current_frame > 0) {
1215 begin_reversible_command (_("select all before cursor"));
1217 end = cursor->current_frame - 1;
1226 if (selection->tracks.empty()) {
1229 ts = &selection->tracks;
1232 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1233 if ((*iter)->hidden()) {
1236 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1238 selection->set (touched);
1239 commit_reversible_command ();
1243 Editor::select_all_selectables_using_edit (bool after)
1247 list<Selectable *> touched;
1250 begin_reversible_command (_("select all after edit"));
1251 start = get_preferred_edit_position();
1252 end = session->current_end_frame();
1254 if ((end = get_preferred_edit_position()) > 1) {
1255 begin_reversible_command (_("select all before edit"));
1266 if (selection->tracks.empty()) {
1269 ts = &selection->tracks;
1272 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1273 if ((*iter)->hidden()) {
1276 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1278 selection->set (touched);
1279 commit_reversible_command ();
1283 Editor::select_all_selectables_between (bool /*within*/)
1287 list<Selectable *> touched;
1289 if (!get_edit_op_range (start, end)) {
1295 if (selection->tracks.empty()) {
1298 ts = &selection->tracks;
1301 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1302 if ((*iter)->hidden()) {
1305 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1308 selection->set (touched);
1312 Editor::select_range_between ()
1317 if (!get_edit_op_range (start, end)) {
1321 set_mouse_mode (MouseRange);
1322 selection->set ((TimeAxisView*) 0, start, end);
1326 Editor::get_edit_op_range (nframes64_t& start, nframes64_t& end) const
1331 /* in range mode, use any existing selection */
1333 if (mouse_mode == MouseRange && !selection->time.empty()) {
1334 /* we know that these are ordered */
1335 start = selection->time.start();
1336 end = selection->time.end_frame();
1340 if (!mouse_frame (m, ignored)) {
1341 /* mouse is not in a canvas, try playhead+selected marker.
1342 this is probably most true when using menus.
1345 if (selection->markers.empty()) {
1349 start = selection->markers.front()->position();
1350 end = session->audible_frame();
1354 switch (_edit_point) {
1355 case EditAtPlayhead:
1356 if (selection->markers.empty()) {
1357 /* use mouse + playhead */
1359 end = session->audible_frame();
1361 /* use playhead + selected marker */
1362 start = session->audible_frame();
1363 end = selection->markers.front()->position();
1368 /* use mouse + selected marker */
1369 if (selection->markers.empty()) {
1371 end = session->audible_frame();
1373 start = selection->markers.front()->position();
1378 case EditAtSelectedMarker:
1379 /* use mouse + selected marker */
1380 if (selection->markers.empty()) {
1382 MessageDialog win (_("No edit range defined"),
1387 win.set_secondary_text (
1388 _("the edit point is Selected Marker\nbut there is no selected marker."));
1391 win.set_default_response (RESPONSE_CLOSE);
1392 win.set_position (Gtk::WIN_POS_MOUSE);
1397 return false; // NO RANGE
1399 start = selection->markers.front()->position();
1413 /* turn range into one delimited by start...end,
1423 Editor::deselect_all ()
1425 selection->clear ();