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 case Selection::Toggle:
187 if (selection->selected (&view)) {
189 selection->remove (&view);
192 selection->add (&view);
197 if (!selection->selected (&view)) {
198 selection->add (&view);
203 if (selection->selected (&view) && selection->tracks.size() > 1) {
205 /* reset track selection if there is only 1 other track
206 selected OR if no_remove is not set (its there to
207 prevent deselecting a multi-track selection
208 when clicking on an already selected track
212 if (selection->tracks.empty()) {
213 selection->set (&view);
214 } else if (selection->tracks.size() == 1 || !no_remove) {
215 selection->set (&view);
220 case Selection::Extend:
221 extend_selection_to_track (view);
227 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
229 if (!clicked_trackview) {
237 set_selected_track (*clicked_trackview, op, no_remove);
241 Editor::set_selected_control_point_from_click (Selection::Operation op, bool no_remove)
243 if (!clicked_control_point) {
247 /* select this point and any others that it represents */
252 x1 = pixel_to_frame (clicked_control_point->get_x() - 10);
253 x2 = pixel_to_frame (clicked_control_point->get_x() + 10);
254 y1 = clicked_control_point->get_x() - 10;
255 y2 = clicked_control_point->get_y() + 10;
257 return select_all_within (x1, x2, y1, y2, selection->tracks, op);
261 Editor::get_relevant_audio_tracks (set<AudioTimeAxisView*>& relevant_tracks)
263 /* step one: get all selected tracks and all tracks in the relevant edit groups */
265 for (TrackSelection::iterator ti = selection->tracks.begin(); ti != selection->tracks.end(); ++ti) {
267 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*ti);
273 RouteGroup* group = atv->route()->edit_group();
275 if (group && group->is_active()) {
277 /* active group for this track, loop over all tracks and get every member of the group */
279 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
281 AudioTimeAxisView* tatv;
283 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
285 if (tatv->route()->edit_group() == group) {
286 relevant_tracks.insert (tatv);
291 relevant_tracks.insert (atv);
298 * Call a slot for a given `basis' track and also for any track that is in the same
300 * @param sl Slot to call.
301 * @param basis Basis track.
305 Editor::mapover_audio_tracks (slot<void,AudioTimeAxisView&,uint32_t> sl, TimeAxisView* basis)
307 AudioTimeAxisView* audio_basis = dynamic_cast<AudioTimeAxisView*> (basis);
308 if (audio_basis == 0) {
312 /* work out the tracks that we will call the slot for; use
313 a set here as it will disallow possible duplicates of the
315 set<AudioTimeAxisView*> tracks;
317 /* always call for the basis */
318 tracks.insert (audio_basis);
320 RouteGroup* group = audio_basis->route()->edit_group();
321 if (group && group->is_active()) {
323 /* the basis is a member of an active edit group; find other members */
324 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
325 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*> (*i);
326 if (v && v->route()->edit_group() == group) {
333 uint32_t const sz = tracks.size ();
334 for (set<AudioTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
340 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t ignored, RegionView* basis, vector<RegionView*>* all_equivs)
342 boost::shared_ptr<Playlist> pl;
343 vector<boost::shared_ptr<Region> > results;
345 boost::shared_ptr<Diskstream> ds;
347 if ((ds = tv.get_diskstream()) == 0) {
352 if (&tv == &basis->get_time_axis_view()) {
353 /* looking in same track as the original */
357 if ((pl = ds->playlist()) != 0) {
358 pl->get_equivalent_regions (basis->region(), results);
361 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
362 if ((marv = tv.view()->find_view (*ir)) != 0) {
363 all_equivs->push_back (marv);
369 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions)
371 mapover_audio_tracks (bind (mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_trackview());
373 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
375 equivalent_regions.push_back (basis);
379 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool no_track_remove)
381 vector<RegionView*> all_equivalent_regions;
384 if (!clicked_regionview || !clicked_audio_trackview) {
389 button_release_can_deselect = false;
392 if (op == Selection::Toggle || op == Selection::Set) {
396 case Selection::Toggle:
398 if (selection->selected (clicked_regionview)) {
401 /* whatever was clicked was selected already; do nothing here but allow
402 the button release to deselect it
405 button_release_can_deselect = true;
409 if (button_release_can_deselect) {
411 /* just remove this one region, but only on a permitted button release */
413 selection->remove (clicked_regionview);
416 /* no more deselect action on button release till a new press
417 finds an already selected object.
420 button_release_can_deselect = false;
428 if (selection->selected (clicked_audio_trackview)) {
429 get_equivalent_regions (clicked_regionview, all_equivalent_regions);
431 all_equivalent_regions.push_back (clicked_regionview);
434 /* add all the equivalent regions, but only on button press */
438 if (!all_equivalent_regions.empty()) {
442 selection->add (all_equivalent_regions);
448 if (!selection->selected (clicked_regionview)) {
450 get_equivalent_regions (clicked_regionview, all_equivalent_regions);
451 selection->set (all_equivalent_regions);
454 /* no commit necessary: clicked on an already selected region */
464 } else if (op == Selection::Extend) {
466 list<Selectable*> results;
467 nframes_t last_frame;
468 nframes_t first_frame;
469 bool same_track = false;
471 /* 1. find the last selected regionview in the track that was clicked in */
474 first_frame = max_frames;
476 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
477 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
479 if ((*x)->region()->last_frame() > last_frame) {
480 last_frame = (*x)->region()->last_frame();
483 if ((*x)->region()->first_frame() < first_frame) {
484 first_frame = (*x)->region()->first_frame();
493 /* 2. figure out the boundaries for our search for new objects */
495 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
497 if (last_frame < clicked_regionview->region()->first_frame()) {
498 first_frame = last_frame;
499 last_frame = clicked_regionview->region()->last_frame();
501 last_frame = first_frame;
502 first_frame = clicked_regionview->region()->first_frame();
506 case OverlapExternal:
507 if (last_frame < clicked_regionview->region()->first_frame()) {
508 first_frame = last_frame;
509 last_frame = clicked_regionview->region()->last_frame();
511 last_frame = first_frame;
512 first_frame = clicked_regionview->region()->first_frame();
516 case OverlapInternal:
517 if (last_frame < clicked_regionview->region()->first_frame()) {
518 first_frame = last_frame;
519 last_frame = clicked_regionview->region()->last_frame();
521 last_frame = first_frame;
522 first_frame = clicked_regionview->region()->first_frame();
528 /* nothing to do except add clicked region to selection, since it
529 overlaps with the existing selection in this track.
536 /* click in a track that has no regions selected, so extend vertically
537 to pick out all regions that are defined by the existing selection
542 first_frame = entered_regionview->region()->position();
543 last_frame = entered_regionview->region()->last_frame();
545 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
546 if ((*i)->region()->position() < first_frame) {
547 first_frame = (*i)->region()->position();
549 if ((*i)->region()->last_frame() + 1 > last_frame) {
550 last_frame = (*i)->region()->last_frame();
555 /* 2. find all the tracks we should select in */
557 set<AudioTimeAxisView*> relevant_tracks;
558 set<AudioTimeAxisView*> already_in_selection;
560 get_relevant_audio_tracks (relevant_tracks);
562 if (relevant_tracks.empty()) {
564 /* no relevant tracks -> no tracks selected .. thus .. if
565 the regionview we're in isn't selected (i.e. we're
566 about to extend to it), then find all tracks between
567 the this one and any selected ones.
570 if (!selection->selected (entered_regionview)) {
572 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&entered_regionview->get_time_axis_view());
576 /* add this track to the ones we will search */
578 relevant_tracks.insert (atv);
580 /* find the track closest to this one that
581 already a selected region.
584 AudioTimeAxisView* closest = 0;
585 int distance = INT_MAX;
586 int key = atv->route()->order_key ("editor");
588 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
590 AudioTimeAxisView* aatv = dynamic_cast<AudioTimeAxisView*>(&(*x)->get_time_axis_view());
592 if (aatv && aatv != atv) {
594 pair<set<AudioTimeAxisView*>::iterator,bool> result;
596 result = already_in_selection.insert (aatv);
599 /* newly added to already_in_selection */
602 int d = aatv->route()->order_key ("editor");
606 if (abs (d) < distance) {
616 /* now add all tracks between that one and this one */
618 int okey = closest->route()->order_key ("editor");
624 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
625 AudioTimeAxisView* aatv = dynamic_cast<AudioTimeAxisView*>(*x);
626 if (aatv && aatv != atv) {
628 int k = aatv->route()->order_key ("editor");
630 if (k >= okey && k <= key) {
632 /* in range but don't add it if
633 it already has tracks selected.
634 this avoids odd selection
635 behaviour that feels wrong.
638 if (find (already_in_selection.begin(),
639 already_in_selection.end(),
640 aatv) == already_in_selection.end()) {
642 relevant_tracks.insert (aatv);
652 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
653 one that was clicked.
656 for (set<AudioTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
657 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
660 /* 4. convert to a vector of audio regions */
662 vector<RegionView*> regions;
664 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
667 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
668 regions.push_back (arv);
672 if (!regions.empty()) {
673 selection->add (regions);
684 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
686 vector<RegionView*> all_equivalent_regions;
688 get_regions_corresponding_to (region, all_equivalent_regions);
690 if (all_equivalent_regions.empty()) {
695 case Selection::Toggle:
696 /* XXX this is not correct */
697 selection->toggle (all_equivalent_regions);
700 selection->set (all_equivalent_regions);
702 case Selection::Extend:
703 selection->add (all_equivalent_regions);
706 selection->add (all_equivalent_regions);
712 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, boost::weak_ptr<Region> weak_r)
715 boost::shared_ptr<Region> r (weak_r.lock());
721 boost::shared_ptr<AudioRegion> ar;
723 if ((ar = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
727 if ((rv = sv->find_view (ar)) == 0) {
731 /* don't reset the selection if its something other than
732 a single other region.
735 if (selection->regions.size() > 1) {
739 begin_reversible_command (_("set selected regions"));
743 commit_reversible_command () ;
749 Editor::track_selection_changed ()
751 switch (selection->tracks.size()){
755 set_selected_mixer_strip (*(selection->tracks.front()));
759 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
760 if (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end()) {
761 (*i)->set_selected (true);
763 (*i)->set_selected (false);
769 Editor::time_selection_changed ()
771 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
772 (*i)->hide_selection ();
775 if (selection->tracks.empty()) {
776 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
777 (*i)->show_selection (selection->time);
780 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
781 (*i)->show_selection (selection->time);
785 if (selection->time.empty()) {
786 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
788 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
794 Editor::region_selection_changed ()
796 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
797 (*i)->set_selected_regionviews (selection->regions);
800 zoomed_to_region = false;
804 Editor::point_selection_changed ()
806 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
807 (*i)->set_selected_points (selection->points);
812 Editor::select_all_in_track (Selection::Operation op)
814 list<Selectable *> touched;
816 if (!clicked_trackview) {
820 clicked_trackview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
823 case Selection::Toggle:
824 selection->add (touched);
827 selection->set (touched);
829 case Selection::Extend:
830 /* meaningless, because we're selecting everything */
833 selection->add (touched);
839 Editor::select_all (Selection::Operation op)
841 list<Selectable *> touched;
843 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
844 if ((*iter)->hidden()) {
847 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
849 begin_reversible_command (_("select all"));
852 selection->add (touched);
854 case Selection::Toggle:
855 selection->add (touched);
858 selection->set (touched);
860 case Selection::Extend:
861 /* meaningless, because we're selecting everything */
864 commit_reversible_command ();
868 Editor::invert_selection_in_track ()
870 list<Selectable *> touched;
872 if (!clicked_trackview) {
876 clicked_trackview->get_inverted_selectables (*selection, touched);
877 selection->set (touched);
881 Editor::invert_selection ()
883 list<Selectable *> touched;
885 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
886 if ((*iter)->hidden()) {
889 (*iter)->get_inverted_selectables (*selection, touched);
892 selection->set (touched);
896 Editor::select_all_within (nframes_t start, nframes_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op)
898 list<Selectable*> touched;
899 list<Selectable*>::size_type n = 0;
900 TrackViewList touched_tracks;
902 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
903 if ((*iter)->hidden()) {
909 (*iter)->get_selectables (start, end, top, bot, touched);
911 if (n != touched.size()) {
912 touched_tracks.push_back (*iter);
916 if (touched.empty()) {
920 if (!touched_tracks.empty()) {
924 selection->add (touched_tracks);
926 case Selection::Toggle:
927 selection->toggle (touched_tracks);
930 selection->set (touched_tracks);
932 case Selection::Extend:
933 /* not defined yet */
938 begin_reversible_command (_("select all within"));
941 selection->add (touched);
943 case Selection::Toggle:
944 selection->toggle (touched);
947 selection->set (touched);
949 case Selection::Extend:
950 /* not defined yet */
954 commit_reversible_command ();
956 return !touched.empty();
960 Editor::set_selection_from_audio_region ()
962 if (selection->regions.empty()) {
966 selection->set (0, selection->regions.start(), selection->regions.end_frame());
967 set_mouse_mode (Editing::MouseRange, false);
971 Editor::set_selection_from_punch()
975 if ((location = session->locations()->auto_punch_location()) == 0) {
979 set_selection_from_range (*location);
983 Editor::set_selection_from_loop()
987 if ((location = session->locations()->auto_loop_location()) == 0) {
990 set_selection_from_range (*location);
994 Editor::set_selection_from_range (Location& loc)
996 begin_reversible_command (_("set selection from range"));
997 selection->set (0, loc.start(), loc.end());
998 commit_reversible_command ();
1000 set_mouse_mode (Editing::MouseRange, false);
1004 Editor::select_all_selectables_using_time_selection ()
1006 list<Selectable *> touched;
1008 if (selection->time.empty()) {
1012 nframes_t start = selection->time[clicked_selection].start;
1013 nframes_t end = selection->time[clicked_selection].end;
1015 if (end - start < 1) {
1021 if (selection->tracks.empty()) {
1024 ts = &selection->tracks;
1027 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1028 if ((*iter)->hidden()) {
1031 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1034 begin_reversible_command (_("select all from range"));
1035 selection->set (touched);
1036 commit_reversible_command ();
1041 Editor::select_all_selectables_using_punch()
1043 Location* location = session->locations()->auto_punch_location();
1044 list<Selectable *> touched;
1046 if (location == 0 || (location->end() - location->start() <= 1)) {
1053 if (selection->tracks.empty()) {
1056 ts = &selection->tracks;
1059 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1060 if ((*iter)->hidden()) {
1063 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1065 begin_reversible_command (_("select all from punch"));
1066 selection->set (touched);
1067 commit_reversible_command ();
1072 Editor::select_all_selectables_using_loop()
1074 Location* location = session->locations()->auto_loop_location();
1075 list<Selectable *> touched;
1077 if (location == 0 || (location->end() - location->start() <= 1)) {
1084 if (selection->tracks.empty()) {
1087 ts = &selection->tracks;
1090 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1091 if ((*iter)->hidden()) {
1094 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1096 begin_reversible_command (_("select all from loop"));
1097 selection->set (touched);
1098 commit_reversible_command ();
1103 Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
1107 list<Selectable *> touched;
1110 begin_reversible_command (_("select all after cursor"));
1111 start = cursor->current_frame ;
1112 end = session->current_end_frame();
1114 if (cursor->current_frame > 0) {
1115 begin_reversible_command (_("select all before cursor"));
1117 end = cursor->current_frame - 1;
1126 if (selection->tracks.empty()) {
1129 ts = &selection->tracks;
1132 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1133 if ((*iter)->hidden()) {
1136 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1138 selection->set (touched);
1139 commit_reversible_command ();
1143 Editor::select_all_selectables_using_edit (bool after)
1147 list<Selectable *> touched;
1150 begin_reversible_command (_("select all after edit"));
1151 start = get_preferred_edit_position();
1152 end = session->current_end_frame();
1154 if ((end = get_preferred_edit_position()) > 1) {
1155 begin_reversible_command (_("select all before edit"));
1166 if (selection->tracks.empty()) {
1169 ts = &selection->tracks;
1172 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1173 if ((*iter)->hidden()) {
1176 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1178 selection->set (touched);
1179 commit_reversible_command ();
1183 Editor::select_all_selectables_between (bool within)
1187 list<Selectable *> touched;
1189 if (!get_edit_op_range (start, end)) {
1195 if (selection->tracks.empty()) {
1198 ts = &selection->tracks;
1201 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1202 if ((*iter)->hidden()) {
1205 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1208 selection->set (touched);
1212 Editor::select_range_between ()
1217 if (!get_edit_op_range (start, end)) {
1221 set_mouse_mode (MouseRange);
1222 selection->set ((TimeAxisView*) 0, start, end);
1226 Editor::get_edit_op_range (nframes64_t& start, nframes64_t& end) const
1231 /* in range mode, use any existing selection */
1233 if (mouse_mode == MouseRange && !selection->time.empty()) {
1234 /* we know that these are ordered */
1235 start = selection->time.start();
1236 end = selection->time.end_frame();
1240 if (!mouse_frame (m, ignored)) {
1241 /* mouse is not in a canvas, try playhead+selected marker.
1242 this is probably most true when using menus.
1245 if (selection->markers.empty()) {
1249 start = selection->markers.front()->position();
1250 end = session->audible_frame();
1254 switch (_edit_point) {
1255 case EditAtPlayhead:
1256 if (selection->markers.empty()) {
1257 /* use mouse + playhead */
1259 end = session->audible_frame();
1261 /* use playhead + selected marker */
1262 start = session->audible_frame();
1263 end = selection->markers.front()->position();
1268 /* use mouse + selected marker */
1269 if (selection->markers.empty()) {
1271 end = session->audible_frame();
1273 start = selection->markers.front()->position();
1278 case EditAtSelectedMarker:
1279 /* use mouse + selected marker */
1280 if (selection->markers.empty()) {
1282 MessageDialog win (_("No edit range defined"),
1287 win.set_secondary_text (
1288 _("the edit point is Selected Marker\nbut there is no selected marker."));
1291 win.set_default_response (RESPONSE_CLOSE);
1292 win.set_position (Gtk::WIN_POS_MOUSE);
1297 return false; // NO RANGE
1299 start = selection->markers.front()->position();
1317 Editor::deselect_all ()
1319 selection->clear ();