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"
42 using namespace ARDOUR;
46 using namespace Gtkmm2ext;
47 using namespace Editing;
49 struct TrackViewByPositionSorter
51 bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
52 return a->y_position < b->y_position;
57 Editor::extend_selection_to_track (TimeAxisView& view)
59 if (selection->selected (&view)) {
60 /* already selected, do nothing */
64 if (selection->tracks.empty()) {
66 if (!selection->selected (&view)) {
67 selection->set (&view);
74 /* something is already selected, so figure out which range of things to add */
76 TrackViewList to_be_added;
77 TrackViewList sorted = track_views;
78 TrackViewByPositionSorter cmp;
79 bool passed_clicked = false;
84 if (!selection->selected (&view)) {
85 to_be_added.push_back (&view);
88 /* figure out if we should go forward or backwards */
90 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
93 passed_clicked = true;
96 if (selection->selected (*i)) {
106 passed_clicked = false;
110 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
113 passed_clicked = true;
117 if (passed_clicked) {
118 if ((*i)->hidden()) {
121 if (selection->selected (*i)) {
123 } else if (!(*i)->hidden()) {
124 to_be_added.push_back (*i);
131 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
134 passed_clicked = true;
138 if (passed_clicked) {
140 if ((*r)->hidden()) {
144 if (selection->selected (*r)) {
146 } else if (!(*r)->hidden()) {
147 to_be_added.push_back (*r);
153 if (!to_be_added.empty()) {
154 selection->add (to_be_added);
162 Editor::select_all_tracks ()
164 selection->set (track_views);
168 Editor::set_selected_track_as_side_effect (bool force)
170 if (!clicked_routeview) {
174 if (!selection->tracks.empty()) {
175 if (!selection->selected (clicked_routeview)) {
176 selection->add (clicked_routeview);
180 selection->set (clicked_routeview);
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_routeview) {
225 set_selected_track (*clicked_routeview, 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_tracks (set<RouteTimeAxisView*>& 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 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*ti);
261 RouteGroup* group = rtv->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 RouteTimeAxisView* trtv;
271 if ((trtv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
273 if (trtv->route()->edit_group() == group) {
274 relevant_tracks.insert (trtv);
279 relevant_tracks.insert (rtv);
285 * Call a slot for a given `basis' track and also for any track that is in the same
287 * @param sl Slot to call.
288 * @param basis Basis track.
292 Editor::mapover_tracks (slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis) const
294 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
295 if (route_basis == 0) {
299 /* work out the tracks that we will call the slot for; use
300 a set here as it will disallow possible duplicates of the
302 set<RouteTimeAxisView*> tracks;
304 /* always call for the basis */
305 tracks.insert (route_basis);
307 RouteGroup* group = route_basis->route()->edit_group();
308 if (group && group->is_active()) {
310 /* the basis is a member of an active edit group; find other members */
311 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
312 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
313 if (v && v->route()->edit_group() == group) {
320 uint32_t const sz = tracks.size ();
321 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
327 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t ignored, RegionView* basis, vector<RegionView*>* all_equivs) const
329 boost::shared_ptr<Playlist> pl;
330 vector<boost::shared_ptr<Region> > results;
332 boost::shared_ptr<Diskstream> ds;
334 if ((ds = tv.get_diskstream()) == 0) {
339 if (&tv == &basis->get_time_axis_view()) {
340 /* looking in same track as the original */
344 if ((pl = ds->playlist()) != 0) {
345 pl->get_equivalent_regions (basis->region(), results);
348 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
349 if ((marv = tv.view()->find_view (*ir)) != 0) {
350 all_equivs->push_back (marv);
356 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions) const
358 mapover_tracks (bind (mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_trackview());
360 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
362 equivalent_regions.push_back (basis);
366 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool no_track_remove)
368 vector<RegionView*> all_equivalent_regions;
371 if (!clicked_regionview || !clicked_routeview) {
376 button_release_can_deselect = false;
379 if (op == Selection::Toggle || op == Selection::Set) {
383 case Selection::Toggle:
385 if (selection->selected (clicked_regionview)) {
388 /* whatever was clicked was selected already; do nothing here but allow
389 the button release to deselect it
392 button_release_can_deselect = true;
396 if (button_release_can_deselect) {
398 /* just remove this one region, but only on a permitted button release */
400 selection->remove (clicked_regionview);
403 /* no more deselect action on button release till a new press
404 finds an already selected object.
407 button_release_can_deselect = false;
415 if (selection->selected (clicked_routeview)) {
416 get_equivalent_regions (clicked_regionview, all_equivalent_regions);
418 all_equivalent_regions.push_back (clicked_regionview);
421 /* add all the equivalent regions, but only on button press */
425 if (!all_equivalent_regions.empty()) {
429 selection->add (all_equivalent_regions);
435 if (!selection->selected (clicked_regionview)) {
436 selection->set (clicked_regionview);
439 /* no commit necessary: clicked on an already selected region */
449 } else if (op == Selection::Extend) {
451 list<Selectable*> results;
452 nframes_t last_frame;
453 nframes_t first_frame;
454 bool same_track = false;
456 /* 1. find the last selected regionview in the track that was clicked in */
459 first_frame = max_frames;
461 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
462 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
464 if ((*x)->region()->last_frame() > last_frame) {
465 last_frame = (*x)->region()->last_frame();
468 if ((*x)->region()->first_frame() < first_frame) {
469 first_frame = (*x)->region()->first_frame();
478 /* 2. figure out the boundaries for our search for new objects */
480 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
482 if (last_frame < clicked_regionview->region()->first_frame()) {
483 first_frame = last_frame;
484 last_frame = clicked_regionview->region()->last_frame();
486 last_frame = first_frame;
487 first_frame = clicked_regionview->region()->first_frame();
491 case OverlapExternal:
492 if (last_frame < clicked_regionview->region()->first_frame()) {
493 first_frame = last_frame;
494 last_frame = clicked_regionview->region()->last_frame();
496 last_frame = first_frame;
497 first_frame = clicked_regionview->region()->first_frame();
501 case OverlapInternal:
502 if (last_frame < clicked_regionview->region()->first_frame()) {
503 first_frame = last_frame;
504 last_frame = clicked_regionview->region()->last_frame();
506 last_frame = first_frame;
507 first_frame = clicked_regionview->region()->first_frame();
513 /* nothing to do except add clicked region to selection, since it
514 overlaps with the existing selection in this track.
521 /* click in a track that has no regions selected, so extend vertically
522 to pick out all regions that are defined by the existing selection
527 first_frame = entered_regionview->region()->position();
528 last_frame = entered_regionview->region()->last_frame();
530 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
531 if ((*i)->region()->position() < first_frame) {
532 first_frame = (*i)->region()->position();
534 if ((*i)->region()->last_frame() + 1 > last_frame) {
535 last_frame = (*i)->region()->last_frame();
540 /* 2. find all the tracks we should select in */
542 set<RouteTimeAxisView*> relevant_tracks;
543 set<RouteTimeAxisView*> already_in_selection;
545 get_relevant_tracks (relevant_tracks);
547 if (relevant_tracks.empty()) {
549 /* no relevant tracks -> no tracks selected .. thus .. if
550 the regionview we're in isn't selected (i.e. we're
551 about to extend to it), then find all tracks between
552 the this one and any selected ones.
555 if (!selection->selected (entered_regionview)) {
557 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&entered_regionview->get_time_axis_view());
561 /* add this track to the ones we will search */
563 relevant_tracks.insert (rtv);
565 /* find the track closest to this one that
566 already a selected region.
569 RouteTimeAxisView* closest = 0;
570 int distance = INT_MAX;
571 int key = rtv->route()->order_key ("editor");
573 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
575 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
577 if (artv && artv != rtv) {
579 pair<set<RouteTimeAxisView*>::iterator,bool> result;
581 result = already_in_selection.insert (artv);
584 /* newly added to already_in_selection */
587 int d = artv->route()->order_key ("editor");
591 if (abs (d) < distance) {
601 /* now add all tracks between that one and this one */
603 int okey = closest->route()->order_key ("editor");
609 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
610 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
611 if (artv && artv != rtv) {
613 int k = artv->route()->order_key ("editor");
615 if (k >= okey && k <= key) {
617 /* in range but don't add it if
618 it already has tracks selected.
619 this avoids odd selection
620 behaviour that feels wrong.
623 if (find (already_in_selection.begin(),
624 already_in_selection.end(),
625 artv) == already_in_selection.end()) {
627 relevant_tracks.insert (artv);
637 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
638 one that was clicked.
641 get_relevant_tracks (relevant_tracks);
643 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
644 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
647 /* 4. convert to a vector of regions */
649 vector<RegionView*> regions;
651 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
654 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
655 regions.push_back (arv);
659 if (!regions.empty()) {
660 selection->add (regions);
671 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
673 vector<RegionView*> all_equivalent_regions;
675 get_regions_corresponding_to (region, all_equivalent_regions);
677 if (all_equivalent_regions.empty()) {
681 begin_reversible_command (_("set selected regions"));
684 case Selection::Toggle:
685 /* XXX this is not correct */
686 selection->toggle (all_equivalent_regions);
689 selection->set (all_equivalent_regions);
691 case Selection::Extend:
692 selection->add (all_equivalent_regions);
695 selection->add (all_equivalent_regions);
699 commit_reversible_command () ;
703 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, boost::weak_ptr<Region> weak_r)
706 boost::shared_ptr<Region> r (weak_r.lock());
712 if ((rv = sv->find_view (r)) == 0) {
716 /* don't reset the selection if its something other than
717 a single other region.
720 if (selection->regions.size() > 1) {
724 begin_reversible_command (_("set selected regions"));
728 commit_reversible_command () ;
734 Editor::track_selection_changed ()
736 switch (selection->tracks.size()){
740 set_selected_mixer_strip (*(selection->tracks.front()));
744 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
745 if (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end()) {
746 (*i)->set_selected (true);
748 (*i)->set_selected (false);
752 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
756 Editor::time_selection_changed ()
758 if (Profile->get_sae()) {
762 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
763 (*i)->hide_selection ();
766 if (selection->tracks.empty()) {
767 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
768 (*i)->show_selection (selection->time);
771 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
772 (*i)->show_selection (selection->time);
776 if (selection->time.empty()) {
777 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
779 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
785 Editor::sensitize_the_right_region_actions (bool have_selected_regions)
787 for (vector<Glib::RefPtr<Action> >::iterator x = ActionManager::region_selection_sensitive_actions.begin();
788 x != ActionManager::region_selection_sensitive_actions.end(); ++x) {
790 string accel_path = (*x)->get_accel_path ();
793 /* if there is an accelerator, it should always be sensitive
794 to allow for keyboard ops on entered regions.
797 bool known = ActionManager::lookup_entry (accel_path, key);
799 if (known && ((key.get_key() != GDK_VoidSymbol) && (key.get_key() != 0))) {
800 (*x)->set_sensitive (true);
802 (*x)->set_sensitive (have_selected_regions);
809 Editor::region_selection_changed ()
811 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
812 (*i)->set_selected_regionviews (selection->regions);
815 sensitize_the_right_region_actions (!selection->regions.empty());
817 zoomed_to_region = false;
821 Editor::point_selection_changed ()
823 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
824 (*i)->set_selected_points (selection->points);
829 Editor::select_all_in_track (Selection::Operation op)
831 list<Selectable *> touched;
833 if (!clicked_routeview) {
837 clicked_routeview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
840 case Selection::Toggle:
841 selection->add (touched);
844 selection->set (touched);
846 case Selection::Extend:
847 /* meaningless, because we're selecting everything */
850 selection->add (touched);
856 Editor::select_all (Selection::Operation op)
858 list<Selectable *> touched;
860 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
861 if ((*iter)->hidden()) {
864 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
866 begin_reversible_command (_("select all"));
869 selection->add (touched);
871 case Selection::Toggle:
872 selection->add (touched);
875 selection->set (touched);
877 case Selection::Extend:
878 /* meaningless, because we're selecting everything */
881 commit_reversible_command ();
884 Editor::invert_selection_in_track ()
886 list<Selectable *> touched;
888 if (!clicked_routeview) {
892 clicked_routeview->get_inverted_selectables (*selection, touched);
893 selection->set (touched);
897 Editor::invert_selection ()
899 list<Selectable *> touched;
901 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
902 if ((*iter)->hidden()) {
905 (*iter)->get_inverted_selectables (*selection, touched);
908 selection->set (touched);
912 Editor::select_all_within (nframes_t start, nframes_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op)
914 list<Selectable*> touched;
915 list<Selectable*>::size_type n = 0;
916 TrackViewList touched_tracks;
918 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
919 if ((*iter)->hidden()) {
925 (*iter)->get_selectables (start, end, top, bot, touched);
927 if (n != touched.size()) {
928 touched_tracks.push_back (*iter);
932 if (touched.empty()) {
936 if (!touched_tracks.empty()) {
940 selection->add (touched_tracks);
942 case Selection::Toggle:
943 selection->toggle (touched_tracks);
946 selection->set (touched_tracks);
948 case Selection::Extend:
949 /* not defined yet */
954 begin_reversible_command (_("select all within"));
957 selection->add (touched);
959 case Selection::Toggle:
960 selection->toggle (touched);
963 selection->set (touched);
965 case Selection::Extend:
966 /* not defined yet */
970 commit_reversible_command ();
972 return !touched.empty();
976 Editor::set_selection_from_region ()
978 if (selection->regions.empty()) {
982 selection->set (0, selection->regions.start(), selection->regions.end_frame());
983 if (!Profile->get_sae()) {
984 set_mouse_mode (Editing::MouseRange, false);
989 Editor::set_selection_from_punch()
993 if ((location = session->locations()->auto_punch_location()) == 0) {
997 set_selection_from_range (*location);
1001 Editor::set_selection_from_loop()
1005 if ((location = session->locations()->auto_loop_location()) == 0) {
1008 set_selection_from_range (*location);
1012 Editor::set_selection_from_range (Location& loc)
1014 begin_reversible_command (_("set selection from range"));
1015 selection->set (0, loc.start(), loc.end());
1016 commit_reversible_command ();
1018 if (!Profile->get_sae()) {
1019 set_mouse_mode (Editing::MouseRange, false);
1024 Editor::select_all_selectables_using_time_selection ()
1026 list<Selectable *> touched;
1028 if (selection->time.empty()) {
1032 nframes_t start = selection->time[clicked_selection].start;
1033 nframes_t end = selection->time[clicked_selection].end;
1035 if (end - start < 1) {
1041 if (selection->tracks.empty()) {
1044 ts = &selection->tracks;
1047 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1048 if ((*iter)->hidden()) {
1051 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1054 begin_reversible_command (_("select all from range"));
1055 selection->set (touched);
1056 commit_reversible_command ();
1061 Editor::select_all_selectables_using_punch()
1063 Location* location = session->locations()->auto_punch_location();
1064 list<Selectable *> touched;
1066 if (location == 0 || (location->end() - location->start() <= 1)) {
1073 if (selection->tracks.empty()) {
1076 ts = &selection->tracks;
1079 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1080 if ((*iter)->hidden()) {
1083 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1085 begin_reversible_command (_("select all from punch"));
1086 selection->set (touched);
1087 commit_reversible_command ();
1092 Editor::select_all_selectables_using_loop()
1094 Location* location = session->locations()->auto_loop_location();
1095 list<Selectable *> touched;
1097 if (location == 0 || (location->end() - location->start() <= 1)) {
1104 if (selection->tracks.empty()) {
1107 ts = &selection->tracks;
1110 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1111 if ((*iter)->hidden()) {
1114 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1116 begin_reversible_command (_("select all from loop"));
1117 selection->set (touched);
1118 commit_reversible_command ();
1123 Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
1127 list<Selectable *> touched;
1130 begin_reversible_command (_("select all after cursor"));
1131 start = cursor->current_frame ;
1132 end = session->current_end_frame();
1134 if (cursor->current_frame > 0) {
1135 begin_reversible_command (_("select all before cursor"));
1137 end = cursor->current_frame - 1;
1146 if (selection->tracks.empty()) {
1149 ts = &selection->tracks;
1152 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1153 if ((*iter)->hidden()) {
1156 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1158 selection->set (touched);
1159 commit_reversible_command ();
1163 Editor::select_all_selectables_using_edit (bool after)
1167 list<Selectable *> touched;
1170 begin_reversible_command (_("select all after edit"));
1171 start = get_preferred_edit_position();
1172 end = session->current_end_frame();
1174 if ((end = get_preferred_edit_position()) > 1) {
1175 begin_reversible_command (_("select all before edit"));
1186 if (selection->tracks.empty()) {
1189 ts = &selection->tracks;
1192 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1193 if ((*iter)->hidden()) {
1196 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1198 selection->set (touched);
1199 commit_reversible_command ();
1203 Editor::select_all_selectables_between (bool within)
1207 list<Selectable *> touched;
1209 if (!get_edit_op_range (start, end)) {
1215 if (selection->tracks.empty()) {
1218 ts = &selection->tracks;
1221 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1222 if ((*iter)->hidden()) {
1225 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1228 selection->set (touched);
1232 Editor::select_range_between ()
1237 if (!get_edit_op_range (start, end)) {
1241 set_mouse_mode (MouseRange);
1242 selection->set ((TimeAxisView*) 0, start, end);
1246 Editor::get_edit_op_range (nframes64_t& start, nframes64_t& end) const
1251 /* in range mode, use any existing selection */
1253 if (mouse_mode == MouseRange && !selection->time.empty()) {
1254 /* we know that these are ordered */
1255 start = selection->time.start();
1256 end = selection->time.end_frame();
1260 if (!mouse_frame (m, ignored)) {
1261 /* mouse is not in a canvas, try playhead+selected marker.
1262 this is probably most true when using menus.
1265 if (selection->markers.empty()) {
1269 start = selection->markers.front()->position();
1270 end = session->audible_frame();
1274 switch (_edit_point) {
1275 case EditAtPlayhead:
1276 if (selection->markers.empty()) {
1277 /* use mouse + playhead */
1279 end = session->audible_frame();
1281 /* use playhead + selected marker */
1282 start = session->audible_frame();
1283 end = selection->markers.front()->position();
1288 /* use mouse + selected marker */
1289 if (selection->markers.empty()) {
1291 end = session->audible_frame();
1293 start = selection->markers.front()->position();
1298 case EditAtSelectedMarker:
1299 /* use mouse + selected marker */
1300 if (selection->markers.empty()) {
1302 MessageDialog win (_("No edit range defined"),
1307 win.set_secondary_text (
1308 _("the edit point is Selected Marker\nbut there is no selected marker."));
1311 win.set_default_response (RESPONSE_CLOSE);
1312 win.set_position (Gtk::WIN_POS_MOUSE);
1317 return false; // NO RANGE
1319 start = selection->markers.front()->position();
1333 /* turn range into one delimited by start...end,
1343 Editor::deselect_all ()
1345 selection->clear ();