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"
35 #include "control_point.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_routeview) {
173 if (!selection->tracks.empty()) {
174 if (!selection->selected (clicked_routeview)) {
175 selection->add (clicked_routeview);
179 selection->set (clicked_routeview);
184 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
187 case Selection::Toggle:
188 if (selection->selected (&view)) {
190 selection->remove (&view);
193 selection->add (&view);
198 if (!selection->selected (&view)) {
199 selection->add (&view);
204 if (selection->selected (&view) && selection->tracks.size() > 1) {
206 /* reset track selection if there is only 1 other track
207 selected OR if no_remove is not set (its there to
208 prevent deselecting a multi-track selection
209 when clicking on an already selected track
213 if (selection->tracks.empty()) {
214 selection->set (&view);
215 } else if (selection->tracks.size() == 1 || !no_remove) {
216 selection->set (&view);
221 case Selection::Extend:
222 extend_selection_to_track (view);
228 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
230 if (!clicked_routeview) {
238 set_selected_track (*clicked_routeview, op, no_remove);
242 Editor::set_selected_control_point_from_click (Selection::Operation op, bool no_remove)
244 if (!clicked_control_point) {
248 /* select this point and any others that it represents */
253 x1 = pixel_to_frame (clicked_control_point->get_x() - 10);
254 x2 = pixel_to_frame (clicked_control_point->get_x() + 10);
255 y1 = clicked_control_point->get_x() - 10;
256 y2 = clicked_control_point->get_y() + 10;
258 return select_all_within (x1, x2, y1, y2, selection->tracks, op);
262 Editor::get_relevant_tracks (set<RouteTimeAxisView*>& relevant_tracks)
264 /* step one: get all selected tracks and all tracks in the relevant edit groups */
266 for (TrackSelection::iterator ti = selection->tracks.begin(); ti != selection->tracks.end(); ++ti) {
268 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*ti);
274 RouteGroup* group = rtv->route()->edit_group();
276 if (group && group->is_active()) {
278 /* active group for this track, loop over all tracks and get every member of the group */
280 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
282 RouteTimeAxisView* trtv;
284 if ((trtv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
286 if (trtv->route()->edit_group() == group) {
287 relevant_tracks.insert (trtv);
292 relevant_tracks.insert (rtv);
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_tracks (slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis) const
307 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
308 if (route_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<RouteTimeAxisView*> tracks;
317 /* always call for the basis */
318 tracks.insert (route_basis);
320 RouteGroup* group = route_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::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
325 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
326 if (v && v->route()->edit_group() == group) {
333 uint32_t const sz = tracks.size ();
334 for (set<RouteTimeAxisView*>::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) const
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) const
371 mapover_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_routeview) {
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_routeview)) {
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)) {
449 selection->set (clicked_regionview);
452 /* no commit necessary: clicked on an already selected region */
462 } else if (op == Selection::Extend) {
464 list<Selectable*> results;
465 nframes_t last_frame;
466 nframes_t first_frame;
467 bool same_track = false;
469 /* 1. find the last selected regionview in the track that was clicked in */
472 first_frame = max_frames;
474 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
475 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
477 if ((*x)->region()->last_frame() > last_frame) {
478 last_frame = (*x)->region()->last_frame();
481 if ((*x)->region()->first_frame() < first_frame) {
482 first_frame = (*x)->region()->first_frame();
491 /* 2. figure out the boundaries for our search for new objects */
493 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
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 OverlapExternal:
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();
514 case OverlapInternal:
515 if (last_frame < clicked_regionview->region()->first_frame()) {
516 first_frame = last_frame;
517 last_frame = clicked_regionview->region()->last_frame();
519 last_frame = first_frame;
520 first_frame = clicked_regionview->region()->first_frame();
526 /* nothing to do except add clicked region to selection, since it
527 overlaps with the existing selection in this track.
534 /* click in a track that has no regions selected, so extend vertically
535 to pick out all regions that are defined by the existing selection
540 first_frame = entered_regionview->region()->position();
541 last_frame = entered_regionview->region()->last_frame();
543 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
544 if ((*i)->region()->position() < first_frame) {
545 first_frame = (*i)->region()->position();
547 if ((*i)->region()->last_frame() + 1 > last_frame) {
548 last_frame = (*i)->region()->last_frame();
553 /* 2. find all the tracks we should select in */
555 set<RouteTimeAxisView*> relevant_tracks;
556 set<RouteTimeAxisView*> already_in_selection;
558 get_relevant_tracks (relevant_tracks);
560 if (relevant_tracks.empty()) {
562 /* no relevant tracks -> no tracks selected .. thus .. if
563 the regionview we're in isn't selected (i.e. we're
564 about to extend to it), then find all tracks between
565 the this one and any selected ones.
568 if (!selection->selected (entered_regionview)) {
570 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&entered_regionview->get_time_axis_view());
574 /* add this track to the ones we will search */
576 relevant_tracks.insert (rtv);
578 /* find the track closest to this one that
579 already a selected region.
582 RouteTimeAxisView* closest = 0;
583 int distance = INT_MAX;
584 int key = rtv->route()->order_key ("editor");
586 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
588 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
590 if (artv && artv != rtv) {
592 pair<set<RouteTimeAxisView*>::iterator,bool> result;
594 result = already_in_selection.insert (artv);
597 /* newly added to already_in_selection */
600 int d = artv->route()->order_key ("editor");
604 if (abs (d) < distance) {
614 /* now add all tracks between that one and this one */
616 int okey = closest->route()->order_key ("editor");
622 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
623 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
624 if (artv && artv != rtv) {
626 int k = artv->route()->order_key ("editor");
628 if (k >= okey && k <= key) {
630 /* in range but don't add it if
631 it already has tracks selected.
632 this avoids odd selection
633 behaviour that feels wrong.
636 if (find (already_in_selection.begin(),
637 already_in_selection.end(),
638 artv) == already_in_selection.end()) {
640 relevant_tracks.insert (artv);
650 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
651 one that was clicked.
654 get_relevant_tracks (relevant_tracks);
656 for (set<RouteTimeAxisView*>::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 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()) {
694 begin_reversible_command (_("set selected regions"));
697 case Selection::Toggle:
698 /* XXX this is not correct */
699 selection->toggle (all_equivalent_regions);
702 selection->set (all_equivalent_regions);
704 case Selection::Extend:
705 selection->add (all_equivalent_regions);
708 selection->add (all_equivalent_regions);
712 commit_reversible_command () ;
716 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, boost::weak_ptr<Region> weak_r)
719 boost::shared_ptr<Region> r (weak_r.lock());
725 if ((rv = sv->find_view (r)) == 0) {
729 /* don't reset the selection if its something other than
730 a single other region.
733 if (selection->regions.size() > 1) {
737 begin_reversible_command (_("set selected regions"));
741 commit_reversible_command () ;
747 Editor::track_selection_changed ()
749 switch (selection->tracks.size()){
753 set_selected_mixer_strip (*(selection->tracks.front()));
757 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
758 if (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end()) {
759 (*i)->set_selected (true);
761 (*i)->set_selected (false);
767 Editor::time_selection_changed ()
769 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
770 (*i)->hide_selection ();
773 if (selection->tracks.empty()) {
774 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
775 (*i)->show_selection (selection->time);
778 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
779 (*i)->show_selection (selection->time);
783 if (selection->time.empty()) {
784 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
786 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
792 Editor::region_selection_changed ()
794 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
795 (*i)->set_selected_regionviews (selection->regions);
798 bool have_selected_regions = !selection->regions.empty();
800 for (vector<Glib::RefPtr<Action> >::iterator x = ActionManager::region_selection_sensitive_actions.begin();
801 x != ActionManager::region_selection_sensitive_actions.end(); ++x) {
803 string accel_path = (*x)->get_accel_path ();
806 /* if there is an accelerator, it should always be sensitive
807 to allow for keyboard ops on entered regions.
810 bool known = ActionManager::lookup_entry (accel_path, key);
812 if (known && ((key.get_key() != GDK_VoidSymbol) && (key.get_key() != 0))) {
813 (*x)->set_sensitive (true);
815 (*x)->set_sensitive (have_selected_regions);
819 zoomed_to_region = false;
823 Editor::point_selection_changed ()
825 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
826 (*i)->set_selected_points (selection->points);
831 Editor::select_all_in_track (Selection::Operation op)
833 list<Selectable *> touched;
835 if (!clicked_routeview) {
839 clicked_routeview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
842 case Selection::Toggle:
843 selection->add (touched);
846 selection->set (touched);
848 case Selection::Extend:
849 /* meaningless, because we're selecting everything */
852 selection->add (touched);
858 Editor::select_all (Selection::Operation op)
860 list<Selectable *> touched;
862 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
863 if ((*iter)->hidden()) {
866 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
868 begin_reversible_command (_("select all"));
871 selection->add (touched);
873 case Selection::Toggle:
874 selection->add (touched);
877 selection->set (touched);
879 case Selection::Extend:
880 /* meaningless, because we're selecting everything */
883 commit_reversible_command ();
886 Editor::invert_selection_in_track ()
888 list<Selectable *> touched;
890 if (!clicked_routeview) {
894 clicked_routeview->get_inverted_selectables (*selection, touched);
895 selection->set (touched);
899 Editor::invert_selection ()
901 list<Selectable *> touched;
903 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
904 if ((*iter)->hidden()) {
907 (*iter)->get_inverted_selectables (*selection, touched);
910 selection->set (touched);
914 Editor::select_all_within (nframes_t start, nframes_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op)
916 list<Selectable*> touched;
917 list<Selectable*>::size_type n = 0;
918 TrackViewList touched_tracks;
920 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
921 if ((*iter)->hidden()) {
927 (*iter)->get_selectables (start, end, top, bot, touched);
929 if (n != touched.size()) {
930 touched_tracks.push_back (*iter);
934 if (touched.empty()) {
938 if (!touched_tracks.empty()) {
942 selection->add (touched_tracks);
944 case Selection::Toggle:
945 selection->toggle (touched_tracks);
948 selection->set (touched_tracks);
950 case Selection::Extend:
951 /* not defined yet */
956 begin_reversible_command (_("select all within"));
959 selection->add (touched);
961 case Selection::Toggle:
962 selection->toggle (touched);
965 selection->set (touched);
967 case Selection::Extend:
968 /* not defined yet */
972 commit_reversible_command ();
974 return !touched.empty();
978 Editor::set_selection_from_region ()
980 if (selection->regions.empty()) {
984 selection->set (0, selection->regions.start(), selection->regions.end_frame());
985 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 set_mouse_mode (Editing::MouseRange, false);
1022 Editor::select_all_selectables_using_time_selection ()
1024 list<Selectable *> touched;
1026 if (selection->time.empty()) {
1030 nframes_t start = selection->time[clicked_selection].start;
1031 nframes_t end = selection->time[clicked_selection].end;
1033 if (end - start < 1) {
1039 if (selection->tracks.empty()) {
1042 ts = &selection->tracks;
1045 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1046 if ((*iter)->hidden()) {
1049 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1052 begin_reversible_command (_("select all from range"));
1053 selection->set (touched);
1054 commit_reversible_command ();
1059 Editor::select_all_selectables_using_punch()
1061 Location* location = session->locations()->auto_punch_location();
1062 list<Selectable *> touched;
1064 if (location == 0 || (location->end() - location->start() <= 1)) {
1071 if (selection->tracks.empty()) {
1074 ts = &selection->tracks;
1077 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1078 if ((*iter)->hidden()) {
1081 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1083 begin_reversible_command (_("select all from punch"));
1084 selection->set (touched);
1085 commit_reversible_command ();
1090 Editor::select_all_selectables_using_loop()
1092 Location* location = session->locations()->auto_loop_location();
1093 list<Selectable *> touched;
1095 if (location == 0 || (location->end() - location->start() <= 1)) {
1102 if (selection->tracks.empty()) {
1105 ts = &selection->tracks;
1108 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1109 if ((*iter)->hidden()) {
1112 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1114 begin_reversible_command (_("select all from loop"));
1115 selection->set (touched);
1116 commit_reversible_command ();
1121 Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
1125 list<Selectable *> touched;
1128 begin_reversible_command (_("select all after cursor"));
1129 start = cursor->current_frame ;
1130 end = session->current_end_frame();
1132 if (cursor->current_frame > 0) {
1133 begin_reversible_command (_("select all before cursor"));
1135 end = cursor->current_frame - 1;
1144 if (selection->tracks.empty()) {
1147 ts = &selection->tracks;
1150 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1151 if ((*iter)->hidden()) {
1154 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1156 selection->set (touched);
1157 commit_reversible_command ();
1161 Editor::select_all_selectables_using_edit (bool after)
1165 list<Selectable *> touched;
1168 begin_reversible_command (_("select all after edit"));
1169 start = get_preferred_edit_position();
1170 end = session->current_end_frame();
1172 if ((end = get_preferred_edit_position()) > 1) {
1173 begin_reversible_command (_("select all before edit"));
1184 if (selection->tracks.empty()) {
1187 ts = &selection->tracks;
1190 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1191 if ((*iter)->hidden()) {
1194 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1196 selection->set (touched);
1197 commit_reversible_command ();
1201 Editor::select_all_selectables_between (bool within)
1205 list<Selectable *> touched;
1207 if (!get_edit_op_range (start, end)) {
1213 if (selection->tracks.empty()) {
1216 ts = &selection->tracks;
1219 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1220 if ((*iter)->hidden()) {
1223 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1226 selection->set (touched);
1230 Editor::select_range_between ()
1235 if (!get_edit_op_range (start, end)) {
1239 set_mouse_mode (MouseRange);
1240 selection->set ((TimeAxisView*) 0, start, end);
1244 Editor::get_edit_op_range (nframes64_t& start, nframes64_t& end) const
1249 /* in range mode, use any existing selection */
1251 if (mouse_mode == MouseRange && !selection->time.empty()) {
1252 /* we know that these are ordered */
1253 start = selection->time.start();
1254 end = selection->time.end_frame();
1258 if (!mouse_frame (m, ignored)) {
1259 /* mouse is not in a canvas, try playhead+selected marker.
1260 this is probably most true when using menus.
1263 if (selection->markers.empty()) {
1267 start = selection->markers.front()->position();
1268 end = session->audible_frame();
1272 switch (_edit_point) {
1273 case EditAtPlayhead:
1274 if (selection->markers.empty()) {
1275 /* use mouse + playhead */
1277 end = session->audible_frame();
1279 /* use playhead + selected marker */
1280 start = session->audible_frame();
1281 end = selection->markers.front()->position();
1286 /* use mouse + selected marker */
1287 if (selection->markers.empty()) {
1289 end = session->audible_frame();
1291 start = selection->markers.front()->position();
1296 case EditAtSelectedMarker:
1297 /* use mouse + selected marker */
1298 if (selection->markers.empty()) {
1300 MessageDialog win (_("No edit range defined"),
1305 win.set_secondary_text (
1306 _("the edit point is Selected Marker\nbut there is no selected marker."));
1309 win.set_default_response (RESPONSE_CLOSE);
1310 win.set_position (Gtk::WIN_POS_MOUSE);
1315 return false; // NO RANGE
1317 start = selection->markers.front()->position();
1335 Editor::deselect_all ()
1337 selection->clear ();