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"
41 using namespace ARDOUR;
45 using namespace Gtkmm2ext;
46 using namespace Editing;
48 struct TrackViewByPositionSorter
50 bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
51 return a->y_position < b->y_position;
56 Editor::extend_selection_to_track (TimeAxisView& view)
58 if (selection->selected (&view)) {
59 /* already selected, do nothing */
63 if (selection->tracks.empty()) {
65 if (!selection->selected (&view)) {
66 selection->set (&view);
73 /* something is already selected, so figure out which range of things to add */
75 TrackViewList to_be_added;
76 TrackViewList sorted = track_views;
77 TrackViewByPositionSorter cmp;
78 bool passed_clicked = false;
83 if (!selection->selected (&view)) {
84 to_be_added.push_back (&view);
87 /* figure out if we should go forward or backwards */
89 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
92 passed_clicked = true;
95 if (selection->selected (*i)) {
105 passed_clicked = false;
109 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
112 passed_clicked = true;
116 if (passed_clicked) {
117 if ((*i)->hidden()) {
120 if (selection->selected (*i)) {
122 } else if (!(*i)->hidden()) {
123 to_be_added.push_back (*i);
130 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
133 passed_clicked = true;
137 if (passed_clicked) {
139 if ((*r)->hidden()) {
143 if (selection->selected (*r)) {
145 } else if (!(*r)->hidden()) {
146 to_be_added.push_back (*r);
152 if (!to_be_added.empty()) {
153 selection->add (to_be_added);
161 Editor::select_all_tracks ()
163 selection->set (track_views);
167 Editor::set_selected_track_as_side_effect (bool force)
169 if (!clicked_trackview) {
173 if (!selection->tracks.empty()) {
175 if (!selection->selected (clicked_trackview)) {
176 selection->add (clicked_trackview);
180 selection->set (clicked_trackview);
185 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
188 case Selection::Toggle:
189 if (selection->selected (&view)) {
191 selection->remove (&view);
194 selection->add (&view);
199 if (!selection->selected (&view)) {
200 selection->add (&view);
205 selection->set (&view);
208 case Selection::Extend:
209 extend_selection_to_track (view);
215 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
217 if (!clicked_trackview) {
225 set_selected_track (*clicked_trackview, op, no_remove);
229 Editor::set_selected_control_point_from_click (Selection::Operation op, bool no_remove)
231 if (!clicked_control_point) {
235 /* select this point and any others that it represents */
240 x1 = pixel_to_frame (clicked_control_point->get_x() - 10);
241 x2 = pixel_to_frame (clicked_control_point->get_x() + 10);
242 y1 = clicked_control_point->get_x() - 10;
243 y2 = clicked_control_point->get_y() + 10;
245 return select_all_within (x1, x2, y1, y2, selection->tracks, op);
249 Editor::get_relevant_audio_tracks (set<AudioTimeAxisView*>& relevant_tracks)
251 /* step one: get all selected tracks and all tracks in the relevant edit groups */
253 for (TrackSelection::iterator ti = selection->tracks.begin(); ti != selection->tracks.end(); ++ti) {
255 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*ti);
261 RouteGroup* group = atv->route()->edit_group();
263 if (group && group->is_active()) {
265 /* active group for this track, loop over all tracks and get every member of the group */
267 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
269 AudioTimeAxisView* tatv;
271 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
273 if (tatv->route()->edit_group() == group) {
274 relevant_tracks.insert (tatv);
279 relevant_tracks.insert (atv);
286 * Call a slot for a given `basis' track and also for any track that is in the same
288 * @param sl Slot to call.
289 * @param basis Basis track.
293 Editor::mapover_audio_tracks (slot<void,AudioTimeAxisView&,uint32_t> sl, TimeAxisView* basis)
295 AudioTimeAxisView* audio_basis = dynamic_cast<AudioTimeAxisView*> (basis);
296 if (audio_basis == 0) {
300 /* work out the tracks that we will call the slot for; use
301 a set here as it will disallow possible duplicates of the
303 set<AudioTimeAxisView*> tracks;
305 /* always call for the basis */
306 tracks.insert (audio_basis);
308 RouteGroup* group = audio_basis->route()->edit_group();
309 if (group && group->is_active()) {
311 /* the basis is a member of an active edit group; find other members */
312 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
313 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*> (*i);
314 if (v && v->route()->edit_group() == group) {
321 uint32_t const sz = tracks.size ();
322 for (set<AudioTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
328 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t ignored, RegionView* basis, vector<RegionView*>* all_equivs)
330 boost::shared_ptr<Playlist> pl;
331 vector<boost::shared_ptr<Region> > results;
333 boost::shared_ptr<Diskstream> ds;
335 if ((ds = tv.get_diskstream()) == 0) {
340 if (&tv == &basis->get_time_axis_view()) {
341 /* looking in same track as the original */
345 if ((pl = ds->playlist()) != 0) {
346 pl->get_equivalent_regions (basis->region(), results);
349 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
350 if ((marv = tv.view()->find_view (*ir)) != 0) {
351 all_equivs->push_back (marv);
357 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions)
359 mapover_audio_tracks (bind (mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_trackview());
361 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
363 equivalent_regions.push_back (basis);
367 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool no_track_remove)
369 vector<RegionView*> all_equivalent_regions;
372 if (!clicked_regionview || !clicked_audio_trackview) {
377 button_release_can_deselect = false;
380 if (op == Selection::Toggle || op == Selection::Set) {
384 case Selection::Toggle:
386 if (selection->selected (clicked_regionview)) {
389 /* whatever was clicked was selected already; do nothing here but allow
390 the button release to deselect it
393 button_release_can_deselect = true;
397 if (button_release_can_deselect) {
399 /* just remove this one region, but only on a permitted button release */
401 selection->remove (clicked_regionview);
404 /* no more deselect action on button release till a new press
405 finds an already selected object.
408 button_release_can_deselect = false;
416 if (selection->selected (clicked_audio_trackview)) {
417 get_equivalent_regions (clicked_regionview, all_equivalent_regions);
419 all_equivalent_regions.push_back (clicked_regionview);
422 /* add all the equivalent regions, but only on button press */
426 if (!all_equivalent_regions.empty()) {
430 selection->add (all_equivalent_regions);
436 if (!selection->selected (clicked_regionview)) {
438 get_equivalent_regions (clicked_regionview, all_equivalent_regions);
439 selection->set (all_equivalent_regions);
442 /* no commit necessary: clicked on an already selected region */
452 } else if (op == Selection::Extend) {
454 list<Selectable*> results;
455 nframes_t last_frame;
456 nframes_t first_frame;
457 bool same_track = false;
459 /* 1. find the last selected regionview in the track that was clicked in */
462 first_frame = max_frames;
464 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
465 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
467 if ((*x)->region()->last_frame() > last_frame) {
468 last_frame = (*x)->region()->last_frame();
471 if ((*x)->region()->first_frame() < first_frame) {
472 first_frame = (*x)->region()->first_frame();
481 /* 2. figure out the boundaries for our search for new objects */
483 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
485 if (last_frame < clicked_regionview->region()->first_frame()) {
486 first_frame = last_frame;
487 last_frame = clicked_regionview->region()->last_frame();
489 last_frame = first_frame;
490 first_frame = clicked_regionview->region()->first_frame();
494 case OverlapExternal:
495 if (last_frame < clicked_regionview->region()->first_frame()) {
496 first_frame = last_frame;
497 last_frame = clicked_regionview->region()->last_frame();
499 last_frame = first_frame;
500 first_frame = clicked_regionview->region()->first_frame();
504 case OverlapInternal:
505 if (last_frame < clicked_regionview->region()->first_frame()) {
506 first_frame = last_frame;
507 last_frame = clicked_regionview->region()->last_frame();
509 last_frame = first_frame;
510 first_frame = clicked_regionview->region()->first_frame();
516 /* nothing to do except add clicked region to selection, since it
517 overlaps with the existing selection in this track.
524 /* click in a track that has no regions selected, so extend vertically
525 to pick out all regions that are defined by the existing selection
530 first_frame = entered_regionview->region()->position();
531 last_frame = entered_regionview->region()->last_frame();
533 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
534 if ((*i)->region()->position() < first_frame) {
535 first_frame = (*i)->region()->position();
537 if ((*i)->region()->last_frame() + 1 > last_frame) {
538 last_frame = (*i)->region()->last_frame();
543 /* 2. find all the tracks we should select in */
545 set<AudioTimeAxisView*> relevant_tracks;
546 set<AudioTimeAxisView*> already_in_selection;
548 get_relevant_audio_tracks (relevant_tracks);
550 if (relevant_tracks.empty()) {
552 /* no relevant tracks -> no tracks selected .. thus .. if
553 the regionview we're in isn't selected (i.e. we're
554 about to extend to it), then find all tracks between
555 the this one and any selected ones.
558 if (!selection->selected (entered_regionview)) {
560 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&entered_regionview->get_time_axis_view());
564 /* add this track to the ones we will search */
566 relevant_tracks.insert (atv);
568 /* find the track closest to this one that
569 already a selected region.
572 AudioTimeAxisView* closest = 0;
573 int distance = INT_MAX;
574 int key = atv->route()->order_key ("editor");
576 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
578 AudioTimeAxisView* aatv = dynamic_cast<AudioTimeAxisView*>(&(*x)->get_time_axis_view());
580 if (aatv && aatv != atv) {
582 pair<set<AudioTimeAxisView*>::iterator,bool> result;
584 result = already_in_selection.insert (aatv);
587 /* newly added to already_in_selection */
590 int d = aatv->route()->order_key ("editor");
594 if (abs (d) < distance) {
604 /* now add all tracks between that one and this one */
606 int okey = closest->route()->order_key ("editor");
612 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
613 AudioTimeAxisView* aatv = dynamic_cast<AudioTimeAxisView*>(*x);
614 if (aatv && aatv != atv) {
616 int k = aatv->route()->order_key ("editor");
618 if (k >= okey && k <= key) {
620 /* in range but don't add it if
621 it already has tracks selected.
622 this avoids odd selection
623 behaviour that feels wrong.
626 if (find (already_in_selection.begin(),
627 already_in_selection.end(),
628 aatv) == already_in_selection.end()) {
630 relevant_tracks.insert (aatv);
640 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
641 one that was clicked.
644 for (set<AudioTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
645 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
648 /* 4. convert to a vector of audio regions */
650 vector<RegionView*> regions;
652 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
655 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
656 regions.push_back (arv);
660 if (!regions.empty()) {
661 selection->add (regions);
672 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
674 vector<RegionView*> all_equivalent_regions;
676 get_regions_corresponding_to (region, all_equivalent_regions);
678 if (all_equivalent_regions.empty()) {
683 case Selection::Toggle:
684 /* XXX this is not correct */
685 selection->toggle (all_equivalent_regions);
688 selection->set (all_equivalent_regions);
690 case Selection::Extend:
691 selection->add (all_equivalent_regions);
694 selection->add (all_equivalent_regions);
700 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, boost::weak_ptr<Region> weak_r)
703 boost::shared_ptr<Region> r (weak_r.lock());
709 boost::shared_ptr<AudioRegion> ar;
711 if ((ar = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
715 if ((rv = sv->find_view (ar)) == 0) {
719 /* don't reset the selection if its something other than
720 a single other region.
723 if (selection->regions.size() > 1) {
727 begin_reversible_command (_("set selected regions"));
731 commit_reversible_command () ;
737 Editor::track_selection_changed ()
739 switch (selection->tracks.size()){
743 set_selected_mixer_strip (*(selection->tracks.front()));
747 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
748 if (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end()) {
749 (*i)->set_selected (true);
751 (*i)->set_selected (false);
755 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
759 Editor::time_selection_changed ()
761 if (Profile->get_sae()) {
765 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
766 (*i)->hide_selection ();
769 if (selection->tracks.empty()) {
770 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
771 (*i)->show_selection (selection->time);
774 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
775 (*i)->show_selection (selection->time);
779 if (selection->time.empty()) {
780 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
782 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
788 Editor::sensitize_the_right_region_actions (bool have_selected_regions)
790 for (vector<Glib::RefPtr<Action> >::iterator x = ActionManager::region_selection_sensitive_actions.begin();
791 x != ActionManager::region_selection_sensitive_actions.end(); ++x) {
793 string accel_path = (*x)->get_accel_path ();
796 /* if there is an accelerator, it should always be sensitive
797 to allow for keyboard ops on entered regions.
800 bool known = ActionManager::lookup_entry (accel_path, key);
802 if (known && ((key.get_key() != GDK_VoidSymbol) && (key.get_key() != 0))) {
803 (*x)->set_sensitive (true);
805 (*x)->set_sensitive (have_selected_regions);
812 Editor::region_selection_changed ()
814 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
815 (*i)->set_selected_regionviews (selection->regions);
818 sensitize_the_right_region_actions (!selection->regions.empty());
820 zoomed_to_region = false;
824 Editor::point_selection_changed ()
826 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
827 (*i)->set_selected_points (selection->points);
832 Editor::select_all_in_track (Selection::Operation op)
834 list<Selectable *> touched;
836 if (!clicked_trackview) {
840 clicked_trackview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
843 case Selection::Toggle:
844 selection->add (touched);
847 selection->set (touched);
849 case Selection::Extend:
850 /* meaningless, because we're selecting everything */
853 selection->add (touched);
859 Editor::select_all (Selection::Operation op)
861 list<Selectable *> touched;
863 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
864 if ((*iter)->hidden()) {
867 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
869 begin_reversible_command (_("select all"));
872 selection->add (touched);
874 case Selection::Toggle:
875 selection->add (touched);
878 selection->set (touched);
880 case Selection::Extend:
881 /* meaningless, because we're selecting everything */
884 commit_reversible_command ();
888 Editor::invert_selection_in_track ()
890 list<Selectable *> touched;
892 if (!clicked_trackview) {
896 clicked_trackview->get_inverted_selectables (*selection, touched);
897 selection->set (touched);
901 Editor::invert_selection ()
903 list<Selectable *> touched;
905 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
906 if ((*iter)->hidden()) {
909 (*iter)->get_inverted_selectables (*selection, touched);
912 selection->set (touched);
916 Editor::select_all_within (nframes_t start, nframes_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op)
918 list<Selectable*> touched;
919 list<Selectable*>::size_type n = 0;
920 TrackViewList touched_tracks;
922 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
923 if ((*iter)->hidden()) {
929 (*iter)->get_selectables (start, end, top, bot, touched);
931 if (n != touched.size()) {
932 touched_tracks.push_back (*iter);
936 if (touched.empty()) {
940 if (!touched_tracks.empty()) {
944 selection->add (touched_tracks);
946 case Selection::Toggle:
947 selection->toggle (touched_tracks);
950 selection->set (touched_tracks);
952 case Selection::Extend:
953 /* not defined yet */
958 begin_reversible_command (_("select all within"));
961 selection->add (touched);
963 case Selection::Toggle:
964 selection->toggle (touched);
967 selection->set (touched);
969 case Selection::Extend:
970 /* not defined yet */
974 commit_reversible_command ();
976 return !touched.empty();
980 Editor::set_selection_from_audio_region ()
982 if (selection->regions.empty()) {
986 selection->set (0, selection->regions.start(), selection->regions.end_frame());
987 if (!Profile->get_sae()) {
988 set_mouse_mode (Editing::MouseRange, false);
993 Editor::set_selection_from_punch()
997 if ((location = session->locations()->auto_punch_location()) == 0) {
1001 set_selection_from_range (*location);
1005 Editor::set_selection_from_loop()
1009 if ((location = session->locations()->auto_loop_location()) == 0) {
1012 set_selection_from_range (*location);
1016 Editor::set_selection_from_range (Location& loc)
1018 begin_reversible_command (_("set selection from range"));
1019 selection->set (0, loc.start(), loc.end());
1020 commit_reversible_command ();
1022 if (!Profile->get_sae()) {
1023 set_mouse_mode (Editing::MouseRange, false);
1028 Editor::select_all_selectables_using_time_selection ()
1030 list<Selectable *> touched;
1032 if (selection->time.empty()) {
1036 nframes_t start = selection->time[clicked_selection].start;
1037 nframes_t end = selection->time[clicked_selection].end;
1039 if (end - start < 1) {
1045 if (selection->tracks.empty()) {
1048 ts = &selection->tracks;
1051 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1052 if ((*iter)->hidden()) {
1055 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1058 begin_reversible_command (_("select all from range"));
1059 selection->set (touched);
1060 commit_reversible_command ();
1065 Editor::select_all_selectables_using_punch()
1067 Location* location = session->locations()->auto_punch_location();
1068 list<Selectable *> touched;
1070 if (location == 0 || (location->end() - location->start() <= 1)) {
1077 if (selection->tracks.empty()) {
1080 ts = &selection->tracks;
1083 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1084 if ((*iter)->hidden()) {
1087 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1089 begin_reversible_command (_("select all from punch"));
1090 selection->set (touched);
1091 commit_reversible_command ();
1096 Editor::select_all_selectables_using_loop()
1098 Location* location = session->locations()->auto_loop_location();
1099 list<Selectable *> touched;
1101 if (location == 0 || (location->end() - location->start() <= 1)) {
1108 if (selection->tracks.empty()) {
1111 ts = &selection->tracks;
1114 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1115 if ((*iter)->hidden()) {
1118 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1120 begin_reversible_command (_("select all from loop"));
1121 selection->set (touched);
1122 commit_reversible_command ();
1127 Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
1131 list<Selectable *> touched;
1134 begin_reversible_command (_("select all after cursor"));
1135 start = cursor->current_frame ;
1136 end = session->current_end_frame();
1138 if (cursor->current_frame > 0) {
1139 begin_reversible_command (_("select all before cursor"));
1141 end = cursor->current_frame - 1;
1150 if (selection->tracks.empty()) {
1153 ts = &selection->tracks;
1156 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1157 if ((*iter)->hidden()) {
1160 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1162 selection->set (touched);
1163 commit_reversible_command ();
1167 Editor::select_all_selectables_using_edit (bool after)
1171 list<Selectable *> touched;
1174 begin_reversible_command (_("select all after edit"));
1175 start = get_preferred_edit_position();
1176 end = session->current_end_frame();
1178 if ((end = get_preferred_edit_position()) > 1) {
1179 begin_reversible_command (_("select all before edit"));
1190 if (selection->tracks.empty()) {
1193 ts = &selection->tracks;
1196 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1197 if ((*iter)->hidden()) {
1200 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1202 selection->set (touched);
1203 commit_reversible_command ();
1207 Editor::select_all_selectables_between (bool within)
1211 list<Selectable *> touched;
1213 if (!get_edit_op_range (start, end)) {
1219 if (selection->tracks.empty()) {
1222 ts = &selection->tracks;
1225 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1226 if ((*iter)->hidden()) {
1229 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1232 selection->set (touched);
1236 Editor::select_range_between ()
1241 if (!get_edit_op_range (start, end)) {
1245 set_mouse_mode (MouseRange);
1246 selection->set ((TimeAxisView*) 0, start, end);
1250 Editor::get_edit_op_range (nframes64_t& start, nframes64_t& end) const
1255 /* in range mode, use any existing selection */
1257 if (mouse_mode == MouseRange && !selection->time.empty()) {
1258 /* we know that these are ordered */
1259 start = selection->time.start();
1260 end = selection->time.end_frame();
1264 if (!mouse_frame (m, ignored)) {
1265 /* mouse is not in a canvas, try playhead+selected marker.
1266 this is probably most true when using menus.
1269 if (selection->markers.empty()) {
1273 start = selection->markers.front()->position();
1274 end = session->audible_frame();
1278 switch (_edit_point) {
1279 case EditAtPlayhead:
1280 if (selection->markers.empty()) {
1281 /* use mouse + playhead */
1283 end = session->audible_frame();
1285 /* use playhead + selected marker */
1286 start = session->audible_frame();
1287 end = selection->markers.front()->position();
1292 /* use mouse + selected marker */
1293 if (selection->markers.empty()) {
1295 end = session->audible_frame();
1297 start = selection->markers.front()->position();
1302 case EditAtSelectedMarker:
1303 /* use mouse + selected marker */
1304 if (selection->markers.empty()) {
1306 MessageDialog win (_("No edit range defined"),
1311 win.set_secondary_text (
1312 _("the edit point is Selected Marker\nbut there is no selected marker."));
1315 win.set_default_response (RESPONSE_CLOSE);
1316 win.set_position (Gtk::WIN_POS_MOUSE);
1321 return false; // NO RANGE
1323 start = selection->markers.front()->position();
1337 /* turn range into one delimited by start...end,
1347 Editor::deselect_all ()
1349 selection->clear ();