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>
31 #include "audio_time_axis.h"
32 #include "audio_region_view.h"
33 #include "audio_streamview.h"
34 #include "automation_line.h"
40 using namespace ARDOUR;
44 using namespace Gtkmm2ext;
45 using namespace Editing;
47 struct TrackViewByPositionSorter
49 bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
50 return a->y_position < b->y_position;
55 Editor::extend_selection_to_track (TimeAxisView& view)
57 if (selection->selected (&view)) {
58 /* already selected, do nothing */
62 if (selection->tracks.empty()) {
64 if (!selection->selected (&view)) {
65 selection->set (&view);
72 /* something is already selected, so figure out which range of things to add */
74 TrackViewList to_be_added;
75 TrackViewList sorted = track_views;
76 TrackViewByPositionSorter cmp;
77 bool passed_clicked = false;
82 if (!selection->selected (&view)) {
83 to_be_added.push_back (&view);
86 /* figure out if we should go forward or backwards */
88 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
91 passed_clicked = true;
94 if (selection->selected (*i)) {
104 passed_clicked = false;
108 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
111 passed_clicked = true;
115 if (passed_clicked) {
116 if ((*i)->hidden()) {
119 if (selection->selected (*i)) {
121 } else if (!(*i)->hidden()) {
122 to_be_added.push_back (*i);
129 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
132 passed_clicked = true;
136 if (passed_clicked) {
138 if ((*r)->hidden()) {
142 if (selection->selected (*r)) {
144 } else if (!(*r)->hidden()) {
145 to_be_added.push_back (*r);
151 if (!to_be_added.empty()) {
152 selection->add (to_be_added);
160 Editor::select_all_tracks ()
162 selection->set (track_views);
166 Editor::set_selected_track_as_side_effect (bool force)
168 if (!clicked_trackview) {
172 if (!selection->tracks.empty()) {
173 if (!selection->selected (clicked_trackview)) {
174 selection->add (clicked_trackview);
178 selection->set (clicked_trackview);
183 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
186 cerr << "set selected track, op = " << op << " selected ? " << selection->selected (&view) << " no remove? " << no_remove << endl;
189 case Selection::Toggle:
190 if (selection->selected (&view)) {
192 selection->remove (&view);
195 selection->add (&view);
200 if (!selection->selected (&view)) {
201 selection->add (&view);
206 if (selection->selected (&view) && selection->tracks.size() > 1) {
208 /* reset track selection if there is only 1 other track
209 selected OR if no_remove is not set (its there to
210 prevent deselecting a multi-track selection
211 when clicking on an already selected track
215 if (selection->tracks.empty()) {
216 selection->set (&view);
217 } else if (selection->tracks.size() == 1 || !no_remove) {
218 selection->set (&view);
223 case Selection::Extend:
224 extend_selection_to_track (view);
230 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
232 if (!clicked_trackview) {
240 set_selected_track (*clicked_trackview, op, no_remove);
244 Editor::set_selected_control_point_from_click (Selection::Operation op, bool no_remove)
246 if (!clicked_control_point) {
250 /* select this point and any others that it represents */
255 x1 = pixel_to_frame (clicked_control_point->get_x() - 10);
256 x2 = pixel_to_frame (clicked_control_point->get_x() + 10);
257 y1 = clicked_control_point->get_x() - 10;
258 y2 = clicked_control_point->get_y() + 10;
260 return select_all_within (x1, x2, y1, y2, selection->tracks, op);
264 Editor::get_relevant_audio_tracks (set<AudioTimeAxisView*>& relevant_tracks)
266 /* step one: get all selected tracks and all tracks in the relevant edit groups */
268 for (TrackSelection::iterator ti = selection->tracks.begin(); ti != selection->tracks.end(); ++ti) {
270 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*ti);
276 RouteGroup* group = atv->route()->edit_group();
278 if (group && group->is_active()) {
280 /* active group for this track, loop over all tracks and get every member of the group */
282 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
284 AudioTimeAxisView* tatv;
286 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
288 if (tatv->route()->edit_group() == group) {
289 relevant_tracks.insert (tatv);
294 relevant_tracks.insert (atv);
301 * Call a slot for a given `basis' track and also for any track that is in the same
303 * @param sl Slot to call.
304 * @param basis Basis track.
308 Editor::mapover_audio_tracks (slot<void,AudioTimeAxisView&,uint32_t> sl, TimeAxisView* basis)
310 AudioTimeAxisView* audio_basis = dynamic_cast<AudioTimeAxisView*> (basis);
311 if (audio_basis == 0) {
315 /* work out the tracks that we will call the slot for; use
316 a set here as it will disallow possible duplicates of the
318 set<AudioTimeAxisView*> tracks;
320 /* always call for the basis */
321 tracks.insert (audio_basis);
323 RouteGroup* group = audio_basis->route()->edit_group();
324 if (group && group->is_active()) {
326 /* the basis is a member of an active edit group; find other members */
327 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
328 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*> (*i);
329 if (v && v->route()->edit_group() == group) {
336 uint32_t const sz = tracks.size ();
337 for (set<AudioTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
343 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t ignored, RegionView* basis, vector<RegionView*>* all_equivs)
345 boost::shared_ptr<Playlist> pl;
346 vector<boost::shared_ptr<Region> > results;
348 boost::shared_ptr<Diskstream> ds;
350 if ((ds = tv.get_diskstream()) == 0) {
355 if (&tv == &basis->get_time_axis_view()) {
356 /* looking in same track as the original */
360 if ((pl = ds->playlist()) != 0) {
361 pl->get_equivalent_regions (basis->region(), results);
364 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
365 if ((marv = tv.view()->find_view (*ir)) != 0) {
366 all_equivs->push_back (marv);
372 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions)
374 mapover_audio_tracks (bind (mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_trackview());
376 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
378 equivalent_regions.push_back (basis);
382 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool no_track_remove)
384 vector<RegionView*> all_equivalent_regions;
387 if (!clicked_regionview || !clicked_audio_trackview) {
392 button_release_can_deselect = false;
395 if (op == Selection::Toggle || op == Selection::Set) {
399 case Selection::Toggle:
401 if (selection->selected (clicked_regionview)) {
404 /* whatever was clicked was selected already; do nothing here but allow
405 the button release to deselect it
408 button_release_can_deselect = true;
412 if (button_release_can_deselect) {
414 /* just remove this one region, but only on a permitted button release */
416 selection->remove (clicked_regionview);
419 /* no more deselect action on button release till a new press
420 finds an already selected object.
423 button_release_can_deselect = false;
431 if (selection->selected (clicked_audio_trackview)) {
432 get_equivalent_regions (clicked_regionview, all_equivalent_regions);
434 all_equivalent_regions.push_back (clicked_regionview);
437 /* add all the equivalent regions, but only on button press */
441 if (!all_equivalent_regions.empty()) {
445 selection->add (all_equivalent_regions);
451 if (!selection->selected (clicked_regionview)) {
453 get_equivalent_regions (clicked_regionview, all_equivalent_regions);
454 selection->set (all_equivalent_regions);
457 /* no commit necessary: clicked on an already selected region */
467 } else if (op == Selection::Extend) {
469 list<Selectable*> results;
470 nframes_t last_frame;
471 nframes_t first_frame;
472 bool same_track = false;
474 /* 1. find the last selected regionview in the track that was clicked in */
477 first_frame = max_frames;
479 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
480 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
482 if ((*x)->region()->last_frame() > last_frame) {
483 last_frame = (*x)->region()->last_frame();
486 if ((*x)->region()->first_frame() < first_frame) {
487 first_frame = (*x)->region()->first_frame();
496 /* 2. figure out the boundaries for our search for new objects */
498 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
500 if (last_frame < clicked_regionview->region()->first_frame()) {
501 first_frame = last_frame;
502 last_frame = clicked_regionview->region()->last_frame();
504 last_frame = first_frame;
505 first_frame = clicked_regionview->region()->first_frame();
509 case OverlapExternal:
510 if (last_frame < clicked_regionview->region()->first_frame()) {
511 first_frame = last_frame;
512 last_frame = clicked_regionview->region()->last_frame();
514 last_frame = first_frame;
515 first_frame = clicked_regionview->region()->first_frame();
519 case OverlapInternal:
520 if (last_frame < clicked_regionview->region()->first_frame()) {
521 first_frame = last_frame;
522 last_frame = clicked_regionview->region()->last_frame();
524 last_frame = first_frame;
525 first_frame = clicked_regionview->region()->first_frame();
531 /* nothing to do except add clicked region to selection, since it
532 overlaps with the existing selection in this track.
539 /* click in a track that has no regions selected, so extend vertically
540 to pick out all regions that are defined by the existing selection
545 first_frame = entered_regionview->region()->position();
546 last_frame = entered_regionview->region()->last_frame();
548 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
549 if ((*i)->region()->position() < first_frame) {
550 first_frame = (*i)->region()->position();
552 if ((*i)->region()->last_frame() + 1 > last_frame) {
553 last_frame = (*i)->region()->last_frame();
558 /* 2. find all the tracks we should select in */
560 set<AudioTimeAxisView*> relevant_tracks;
561 set<AudioTimeAxisView*> already_in_selection;
563 get_relevant_audio_tracks (relevant_tracks);
565 if (relevant_tracks.empty()) {
567 /* no relevant tracks -> no tracks selected .. thus .. if
568 the regionview we're in isn't selected (i.e. we're
569 about to extend to it), then find all tracks between
570 the this one and any selected ones.
573 if (!selection->selected (entered_regionview)) {
575 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&entered_regionview->get_time_axis_view());
579 /* add this track to the ones we will search */
581 relevant_tracks.insert (atv);
583 /* find the track closest to this one that
584 already a selected region.
587 AudioTimeAxisView* closest = 0;
588 int distance = INT_MAX;
589 int key = atv->route()->order_key ("editor");
591 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
593 AudioTimeAxisView* aatv = dynamic_cast<AudioTimeAxisView*>(&(*x)->get_time_axis_view());
595 if (aatv && aatv != atv) {
597 pair<set<AudioTimeAxisView*>::iterator,bool> result;
599 result = already_in_selection.insert (aatv);
602 /* newly added to already_in_selection */
605 int d = aatv->route()->order_key ("editor");
609 if (abs (d) < distance) {
619 /* now add all tracks between that one and this one */
621 int okey = closest->route()->order_key ("editor");
627 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
628 AudioTimeAxisView* aatv = dynamic_cast<AudioTimeAxisView*>(*x);
629 if (aatv && aatv != atv) {
631 int k = aatv->route()->order_key ("editor");
633 if (k >= okey && k <= key) {
635 /* in range but don't add it if
636 it already has tracks selected.
637 this avoids odd selection
638 behaviour that feels wrong.
641 if (find (already_in_selection.begin(),
642 already_in_selection.end(),
643 aatv) == already_in_selection.end()) {
645 relevant_tracks.insert (aatv);
655 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
656 one that was clicked.
659 for (set<AudioTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
660 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
663 /* 4. convert to a vector of audio regions */
665 vector<RegionView*> regions;
667 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
670 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
671 regions.push_back (arv);
675 if (!regions.empty()) {
676 selection->add (regions);
687 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
689 vector<RegionView*> all_equivalent_regions;
691 get_regions_corresponding_to (region, all_equivalent_regions);
693 if (all_equivalent_regions.empty()) {
698 case Selection::Toggle:
699 /* XXX this is not correct */
700 selection->toggle (all_equivalent_regions);
703 selection->set (all_equivalent_regions);
705 case Selection::Extend:
706 selection->add (all_equivalent_regions);
709 selection->add (all_equivalent_regions);
715 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, boost::weak_ptr<Region> weak_r)
718 boost::shared_ptr<Region> r (weak_r.lock());
724 boost::shared_ptr<AudioRegion> ar;
726 if ((ar = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
730 if ((rv = sv->find_view (ar)) == 0) {
734 /* don't reset the selection if its something other than
735 a single other region.
738 if (selection->regions.size() > 1) {
742 begin_reversible_command (_("set selected regions"));
746 commit_reversible_command () ;
752 Editor::track_selection_changed ()
754 switch (selection->tracks.size()){
758 set_selected_mixer_strip (*(selection->tracks.front()));
762 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
763 if (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end()) {
764 (*i)->set_selected (true);
766 (*i)->set_selected (false);
772 Editor::time_selection_changed ()
774 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
775 (*i)->hide_selection ();
778 if (selection->tracks.empty()) {
779 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
780 (*i)->show_selection (selection->time);
783 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
784 (*i)->show_selection (selection->time);
788 if (selection->time.empty()) {
789 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
791 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
797 Editor::region_selection_changed ()
799 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
800 (*i)->set_selected_regionviews (selection->regions);
803 zoomed_to_region = false;
807 Editor::point_selection_changed ()
809 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
810 (*i)->set_selected_points (selection->points);
815 Editor::select_all_in_track (Selection::Operation op)
817 list<Selectable *> touched;
819 if (!clicked_trackview) {
823 clicked_trackview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
826 case Selection::Toggle:
827 selection->add (touched);
830 selection->set (touched);
832 case Selection::Extend:
833 /* meaningless, because we're selecting everything */
836 selection->add (touched);
842 Editor::select_all (Selection::Operation op)
844 list<Selectable *> touched;
846 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
847 if ((*iter)->hidden()) {
850 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
852 begin_reversible_command (_("select all"));
855 selection->add (touched);
857 case Selection::Toggle:
858 selection->add (touched);
861 selection->set (touched);
863 case Selection::Extend:
864 /* meaningless, because we're selecting everything */
867 commit_reversible_command ();
871 Editor::invert_selection_in_track ()
873 list<Selectable *> touched;
875 if (!clicked_trackview) {
879 clicked_trackview->get_inverted_selectables (*selection, touched);
880 selection->set (touched);
884 Editor::invert_selection ()
886 list<Selectable *> touched;
888 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
889 if ((*iter)->hidden()) {
892 (*iter)->get_inverted_selectables (*selection, touched);
895 selection->set (touched);
899 Editor::select_all_within (nframes_t start, nframes_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op)
901 list<Selectable*> touched;
902 list<Selectable*>::size_type n = 0;
903 TrackViewList touched_tracks;
905 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
906 if ((*iter)->hidden()) {
912 (*iter)->get_selectables (start, end, top, bot, touched);
914 if (n != touched.size()) {
915 touched_tracks.push_back (*iter);
919 if (touched.empty()) {
923 if (!touched_tracks.empty()) {
927 selection->add (touched_tracks);
929 case Selection::Toggle:
930 selection->toggle (touched_tracks);
933 selection->set (touched_tracks);
935 case Selection::Extend:
936 /* not defined yet */
941 begin_reversible_command (_("select all within"));
944 selection->add (touched);
946 case Selection::Toggle:
947 selection->toggle (touched);
950 selection->set (touched);
952 case Selection::Extend:
953 /* not defined yet */
957 commit_reversible_command ();
959 return !touched.empty();
963 Editor::set_selection_from_audio_region ()
965 if (selection->regions.empty()) {
969 RegionView* rv = *(selection->regions.begin());
970 boost::shared_ptr<Region> region = rv->region();
972 begin_reversible_command (_("set selection from region"));
973 selection->set (0, region->position(), region->last_frame());
974 commit_reversible_command ();
976 set_mouse_mode (Editing::MouseRange, false);
980 Editor::set_selection_from_punch()
984 if ((location = session->locations()->auto_punch_location()) == 0) {
988 set_selection_from_range (*location);
992 Editor::set_selection_from_loop()
996 if ((location = session->locations()->auto_loop_location()) == 0) {
999 set_selection_from_range (*location);
1003 Editor::set_selection_from_range (Location& loc)
1005 begin_reversible_command (_("set selection from range"));
1006 selection->set (0, loc.start(), loc.end());
1007 commit_reversible_command ();
1009 set_mouse_mode (Editing::MouseRange, false);
1013 Editor::select_all_selectables_using_time_selection ()
1015 list<Selectable *> touched;
1017 if (selection->time.empty()) {
1021 nframes_t start = selection->time[clicked_selection].start;
1022 nframes_t end = selection->time[clicked_selection].end;
1024 if (end - start < 1) {
1030 if (selection->tracks.empty()) {
1033 ts = &selection->tracks;
1036 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1037 if ((*iter)->hidden()) {
1040 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1043 begin_reversible_command (_("select all from range"));
1044 selection->set (touched);
1045 commit_reversible_command ();
1050 Editor::select_all_selectables_using_punch()
1052 Location* location = session->locations()->auto_punch_location();
1053 list<Selectable *> touched;
1055 if (location == 0 || (location->end() - location->start() <= 1)) {
1062 if (selection->tracks.empty()) {
1065 ts = &selection->tracks;
1068 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1069 if ((*iter)->hidden()) {
1072 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1074 begin_reversible_command (_("select all from punch"));
1075 selection->set (touched);
1076 commit_reversible_command ();
1081 Editor::select_all_selectables_using_loop()
1083 Location* location = session->locations()->auto_loop_location();
1084 list<Selectable *> touched;
1086 if (location == 0 || (location->end() - location->start() <= 1)) {
1093 if (selection->tracks.empty()) {
1096 ts = &selection->tracks;
1099 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1100 if ((*iter)->hidden()) {
1103 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1105 begin_reversible_command (_("select all from loop"));
1106 selection->set (touched);
1107 commit_reversible_command ();
1112 Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
1116 list<Selectable *> touched;
1119 begin_reversible_command (_("select all after cursor"));
1120 start = cursor->current_frame ;
1121 end = session->current_end_frame();
1123 if (cursor->current_frame > 0) {
1124 begin_reversible_command (_("select all before cursor"));
1126 end = cursor->current_frame - 1;
1135 if (selection->tracks.empty()) {
1138 ts = &selection->tracks;
1141 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1142 if ((*iter)->hidden()) {
1145 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1147 selection->set (touched);
1148 commit_reversible_command ();
1152 Editor::select_all_selectables_using_edit (bool after)
1156 list<Selectable *> touched;
1159 begin_reversible_command (_("select all after edit"));
1160 start = get_preferred_edit_position();
1161 end = session->current_end_frame();
1163 if ((end = get_preferred_edit_position()) > 1) {
1164 begin_reversible_command (_("select all before edit"));
1175 if (selection->tracks.empty()) {
1178 ts = &selection->tracks;
1181 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1182 if ((*iter)->hidden()) {
1185 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1187 selection->set (touched);
1188 commit_reversible_command ();
1192 Editor::select_all_selectables_between (bool within)
1196 list<Selectable *> touched;
1198 if (!get_edit_op_range (start, end)) {
1204 if (selection->tracks.empty()) {
1207 ts = &selection->tracks;
1210 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1211 if ((*iter)->hidden()) {
1214 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1217 selection->set (touched);
1221 Editor::select_range_between ()
1226 if (!get_edit_op_range (start, end)) {
1230 set_mouse_mode (MouseRange);
1231 selection->set ((TimeAxisView*) 0, start, end);
1235 Editor::get_edit_op_range (nframes64_t& start, nframes64_t& end) const
1240 /* in range mode, use any existing selection */
1242 if (mouse_mode == MouseRange && !selection->time.empty()) {
1243 /* we know that these are ordered */
1244 start = selection->time.start();
1245 end = selection->time.end_frame();
1249 if (!mouse_frame (m, ignored)) {
1250 /* mouse is not in a canvas, try playhead+selected marker.
1251 this is probably most true when using menus.
1254 if (selection->markers.empty()) {
1258 start = selection->markers.front()->position();
1259 end = session->audible_frame();
1263 switch (_edit_point) {
1264 case EditAtPlayhead:
1265 if (selection->markers.empty()) {
1266 /* use mouse + playhead */
1268 end = session->audible_frame();
1270 /* use playhead + selected marker */
1271 start = session->audible_frame();
1272 end = selection->markers.front()->position();
1277 /* use mouse + selected marker */
1278 if (selection->markers.empty()) {
1280 end = session->audible_frame();
1282 start = selection->markers.front()->position();
1287 case EditAtSelectedMarker:
1288 /* use mouse + selected marker */
1289 if (selection->markers.empty()) {
1291 MessageDialog win (_("No edit range defined"),
1296 win.set_secondary_text (
1297 _("the edit point is Selected Marker\nbut there is no selected marker."));
1300 win.set_default_response (RESPONSE_CLOSE);
1301 win.set_position (Gtk::WIN_POS_MOUSE);
1306 return false; // NO RANGE
1308 start = selection->markers.front()->position();
1326 Editor::deselect_all ()
1328 selection->clear ();
1331 Editor::ExclusiveRegionSelection::ExclusiveRegionSelection (Editor& ed, RegionView* rv)
1336 if (!rv || ed.current_mouse_mode() != Editing::MouseObject) {
1340 if (ed.get_selection().regions.empty() && !ed.get_selection().selected (rv)) {
1341 ed.get_selection().set (rv, false);
1348 Editor::ExclusiveRegionSelection::~ExclusiveRegionSelection ()
1350 if (remove && regionview) {
1351 editor.get_selection().remove (regionview);