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 if (selection->selected (&view) && selection->tracks.size() > 1) {
207 /* reset track selection if there is only 1 other track
208 selected OR if no_remove is not set (its there to
209 prevent deselecting a multi-track selection
210 when clicking on an already selected track
214 if (selection->tracks.empty()) {
215 selection->set (&view);
216 } else if (selection->tracks.size() == 1 || !no_remove) {
217 selection->set (&view);
222 case Selection::Extend:
223 extend_selection_to_track (view);
229 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
231 if (!clicked_routeview) {
239 set_selected_track (*clicked_routeview, op, no_remove);
243 Editor::set_selected_control_point_from_click (Selection::Operation op, bool no_remove)
245 if (!clicked_control_point) {
249 /* select this point and any others that it represents */
254 x1 = pixel_to_frame (clicked_control_point->get_x() - 10);
255 x2 = pixel_to_frame (clicked_control_point->get_x() + 10);
256 y1 = clicked_control_point->get_x() - 10;
257 y2 = clicked_control_point->get_y() + 10;
259 return select_all_within (x1, x2, y1, y2, selection->tracks, op);
263 Editor::get_relevant_tracks (set<RouteTimeAxisView*>& relevant_tracks)
265 /* step one: get all selected tracks and all tracks in the relevant edit groups */
267 for (TrackSelection::iterator ti = selection->tracks.begin(); ti != selection->tracks.end(); ++ti) {
269 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*ti);
275 RouteGroup* group = rtv->route()->edit_group();
277 if (group && group->is_active()) {
279 /* active group for this track, loop over all tracks and get every member of the group */
281 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
283 RouteTimeAxisView* trtv;
285 if ((trtv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
287 if (trtv->route()->edit_group() == group) {
288 relevant_tracks.insert (trtv);
293 relevant_tracks.insert (rtv);
299 * Call a slot for a given `basis' track and also for any track that is in the same
301 * @param sl Slot to call.
302 * @param basis Basis track.
306 Editor::mapover_tracks (slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis) const
308 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
309 if (route_basis == 0) {
313 /* work out the tracks that we will call the slot for; use
314 a set here as it will disallow possible duplicates of the
316 set<RouteTimeAxisView*> tracks;
318 /* always call for the basis */
319 tracks.insert (route_basis);
321 RouteGroup* group = route_basis->route()->edit_group();
322 if (group && group->is_active()) {
324 /* the basis is a member of an active edit group; find other members */
325 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
326 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
327 if (v && v->route()->edit_group() == group) {
334 uint32_t const sz = tracks.size ();
335 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
341 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t ignored, RegionView* basis, vector<RegionView*>* all_equivs) const
343 boost::shared_ptr<Playlist> pl;
344 vector<boost::shared_ptr<Region> > results;
346 boost::shared_ptr<Diskstream> ds;
348 if ((ds = tv.get_diskstream()) == 0) {
353 if (&tv == &basis->get_time_axis_view()) {
354 /* looking in same track as the original */
358 if ((pl = ds->playlist()) != 0) {
359 pl->get_equivalent_regions (basis->region(), results);
362 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
363 if ((marv = tv.view()->find_view (*ir)) != 0) {
364 all_equivs->push_back (marv);
370 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions) const
372 mapover_tracks (bind (mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_trackview());
374 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
376 equivalent_regions.push_back (basis);
380 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool no_track_remove)
382 vector<RegionView*> all_equivalent_regions;
385 if (!clicked_regionview || !clicked_routeview) {
390 button_release_can_deselect = false;
393 if (op == Selection::Toggle || op == Selection::Set) {
397 case Selection::Toggle:
399 if (selection->selected (clicked_regionview)) {
402 /* whatever was clicked was selected already; do nothing here but allow
403 the button release to deselect it
406 button_release_can_deselect = true;
410 if (button_release_can_deselect) {
412 /* just remove this one region, but only on a permitted button release */
414 selection->remove (clicked_regionview);
417 /* no more deselect action on button release till a new press
418 finds an already selected object.
421 button_release_can_deselect = false;
429 if (selection->selected (clicked_routeview)) {
430 get_equivalent_regions (clicked_regionview, all_equivalent_regions);
432 all_equivalent_regions.push_back (clicked_regionview);
435 /* add all the equivalent regions, but only on button press */
439 if (!all_equivalent_regions.empty()) {
443 selection->add (all_equivalent_regions);
449 if (!selection->selected (clicked_regionview)) {
450 selection->set (clicked_regionview);
453 /* no commit necessary: clicked on an already selected region */
463 } else if (op == Selection::Extend) {
465 list<Selectable*> results;
466 nframes_t last_frame;
467 nframes_t first_frame;
468 bool same_track = false;
470 /* 1. find the last selected regionview in the track that was clicked in */
473 first_frame = max_frames;
475 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
476 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
478 if ((*x)->region()->last_frame() > last_frame) {
479 last_frame = (*x)->region()->last_frame();
482 if ((*x)->region()->first_frame() < first_frame) {
483 first_frame = (*x)->region()->first_frame();
492 /* 2. figure out the boundaries for our search for new objects */
494 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
496 if (last_frame < clicked_regionview->region()->first_frame()) {
497 first_frame = last_frame;
498 last_frame = clicked_regionview->region()->last_frame();
500 last_frame = first_frame;
501 first_frame = clicked_regionview->region()->first_frame();
505 case OverlapExternal:
506 if (last_frame < clicked_regionview->region()->first_frame()) {
507 first_frame = last_frame;
508 last_frame = clicked_regionview->region()->last_frame();
510 last_frame = first_frame;
511 first_frame = clicked_regionview->region()->first_frame();
515 case OverlapInternal:
516 if (last_frame < clicked_regionview->region()->first_frame()) {
517 first_frame = last_frame;
518 last_frame = clicked_regionview->region()->last_frame();
520 last_frame = first_frame;
521 first_frame = clicked_regionview->region()->first_frame();
527 /* nothing to do except add clicked region to selection, since it
528 overlaps with the existing selection in this track.
535 /* click in a track that has no regions selected, so extend vertically
536 to pick out all regions that are defined by the existing selection
541 first_frame = entered_regionview->region()->position();
542 last_frame = entered_regionview->region()->last_frame();
544 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
545 if ((*i)->region()->position() < first_frame) {
546 first_frame = (*i)->region()->position();
548 if ((*i)->region()->last_frame() + 1 > last_frame) {
549 last_frame = (*i)->region()->last_frame();
554 /* 2. find all the tracks we should select in */
556 set<RouteTimeAxisView*> relevant_tracks;
557 set<RouteTimeAxisView*> already_in_selection;
559 get_relevant_tracks (relevant_tracks);
561 if (relevant_tracks.empty()) {
563 /* no relevant tracks -> no tracks selected .. thus .. if
564 the regionview we're in isn't selected (i.e. we're
565 about to extend to it), then find all tracks between
566 the this one and any selected ones.
569 if (!selection->selected (entered_regionview)) {
571 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&entered_regionview->get_time_axis_view());
575 /* add this track to the ones we will search */
577 relevant_tracks.insert (rtv);
579 /* find the track closest to this one that
580 already a selected region.
583 RouteTimeAxisView* closest = 0;
584 int distance = INT_MAX;
585 int key = rtv->route()->order_key ("editor");
587 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
589 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
591 if (artv && artv != rtv) {
593 pair<set<RouteTimeAxisView*>::iterator,bool> result;
595 result = already_in_selection.insert (artv);
598 /* newly added to already_in_selection */
601 int d = artv->route()->order_key ("editor");
605 if (abs (d) < distance) {
615 /* now add all tracks between that one and this one */
617 int okey = closest->route()->order_key ("editor");
623 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
624 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
625 if (artv && artv != rtv) {
627 int k = artv->route()->order_key ("editor");
629 if (k >= okey && k <= key) {
631 /* in range but don't add it if
632 it already has tracks selected.
633 this avoids odd selection
634 behaviour that feels wrong.
637 if (find (already_in_selection.begin(),
638 already_in_selection.end(),
639 artv) == already_in_selection.end()) {
641 relevant_tracks.insert (artv);
651 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
652 one that was clicked.
655 get_relevant_tracks (relevant_tracks);
657 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
658 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
661 /* 4. convert to a vector of regions */
663 vector<RegionView*> regions;
665 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
668 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
669 regions.push_back (arv);
673 if (!regions.empty()) {
674 selection->add (regions);
685 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
687 vector<RegionView*> all_equivalent_regions;
689 get_regions_corresponding_to (region, all_equivalent_regions);
691 if (all_equivalent_regions.empty()) {
695 begin_reversible_command (_("set selected regions"));
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);
713 commit_reversible_command () ;
717 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, boost::weak_ptr<Region> weak_r)
720 boost::shared_ptr<Region> r (weak_r.lock());
726 if ((rv = sv->find_view (r)) == 0) {
730 /* don't reset the selection if its something other than
731 a single other region.
734 if (selection->regions.size() > 1) {
738 begin_reversible_command (_("set selected regions"));
742 commit_reversible_command () ;
748 Editor::track_selection_changed ()
750 switch (selection->tracks.size()){
754 set_selected_mixer_strip (*(selection->tracks.front()));
758 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
759 if (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end()) {
760 (*i)->set_selected (true);
762 (*i)->set_selected (false);
766 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
770 Editor::time_selection_changed ()
772 if (Profile->get_sae()) {
776 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
777 (*i)->hide_selection ();
780 if (selection->tracks.empty()) {
781 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
782 (*i)->show_selection (selection->time);
785 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
786 (*i)->show_selection (selection->time);
790 if (selection->time.empty()) {
791 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
793 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
799 Editor::sensitize_the_right_region_actions (bool have_selected_regions)
801 for (vector<Glib::RefPtr<Action> >::iterator x = ActionManager::region_selection_sensitive_actions.begin();
802 x != ActionManager::region_selection_sensitive_actions.end(); ++x) {
804 string accel_path = (*x)->get_accel_path ();
807 /* if there is an accelerator, it should always be sensitive
808 to allow for keyboard ops on entered regions.
811 bool known = ActionManager::lookup_entry (accel_path, key);
813 if (known && ((key.get_key() != GDK_VoidSymbol) && (key.get_key() != 0))) {
814 (*x)->set_sensitive (true);
816 (*x)->set_sensitive (have_selected_regions);
823 Editor::region_selection_changed ()
825 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
826 (*i)->set_selected_regionviews (selection->regions);
829 sensitize_the_right_region_actions (!selection->regions.empty());
831 zoomed_to_region = false;
835 Editor::point_selection_changed ()
837 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
838 (*i)->set_selected_points (selection->points);
843 Editor::select_all_in_track (Selection::Operation op)
845 list<Selectable *> touched;
847 if (!clicked_routeview) {
851 clicked_routeview->get_selectables (0, max_frames, 0, DBL_MAX, 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 selection->add (touched);
870 Editor::select_all (Selection::Operation op)
872 list<Selectable *> touched;
874 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
875 if ((*iter)->hidden()) {
878 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
880 begin_reversible_command (_("select all"));
883 selection->add (touched);
885 case Selection::Toggle:
886 selection->add (touched);
889 selection->set (touched);
891 case Selection::Extend:
892 /* meaningless, because we're selecting everything */
895 commit_reversible_command ();
898 Editor::invert_selection_in_track ()
900 list<Selectable *> touched;
902 if (!clicked_routeview) {
906 clicked_routeview->get_inverted_selectables (*selection, touched);
907 selection->set (touched);
911 Editor::invert_selection ()
913 list<Selectable *> touched;
915 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
916 if ((*iter)->hidden()) {
919 (*iter)->get_inverted_selectables (*selection, touched);
922 selection->set (touched);
926 Editor::select_all_within (nframes_t start, nframes_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op)
928 list<Selectable*> touched;
929 list<Selectable*>::size_type n = 0;
930 TrackViewList touched_tracks;
932 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
933 if ((*iter)->hidden()) {
939 (*iter)->get_selectables (start, end, top, bot, touched);
941 if (n != touched.size()) {
942 touched_tracks.push_back (*iter);
946 if (touched.empty()) {
950 if (!touched_tracks.empty()) {
954 selection->add (touched_tracks);
956 case Selection::Toggle:
957 selection->toggle (touched_tracks);
960 selection->set (touched_tracks);
962 case Selection::Extend:
963 /* not defined yet */
968 begin_reversible_command (_("select all within"));
971 selection->add (touched);
973 case Selection::Toggle:
974 selection->toggle (touched);
977 selection->set (touched);
979 case Selection::Extend:
980 /* not defined yet */
984 commit_reversible_command ();
986 return !touched.empty();
990 Editor::set_selection_from_region ()
992 if (selection->regions.empty()) {
996 selection->set (0, selection->regions.start(), selection->regions.end_frame());
997 if (!Profile->get_sae()) {
998 set_mouse_mode (Editing::MouseRange, false);
1003 Editor::set_selection_from_punch()
1007 if ((location = session->locations()->auto_punch_location()) == 0) {
1011 set_selection_from_range (*location);
1015 Editor::set_selection_from_loop()
1019 if ((location = session->locations()->auto_loop_location()) == 0) {
1022 set_selection_from_range (*location);
1026 Editor::set_selection_from_range (Location& loc)
1028 begin_reversible_command (_("set selection from range"));
1029 selection->set (0, loc.start(), loc.end());
1030 commit_reversible_command ();
1032 if (!Profile->get_sae()) {
1033 set_mouse_mode (Editing::MouseRange, false);
1038 Editor::select_all_selectables_using_time_selection ()
1040 list<Selectable *> touched;
1042 if (selection->time.empty()) {
1046 nframes_t start = selection->time[clicked_selection].start;
1047 nframes_t end = selection->time[clicked_selection].end;
1049 if (end - start < 1) {
1055 if (selection->tracks.empty()) {
1058 ts = &selection->tracks;
1061 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1062 if ((*iter)->hidden()) {
1065 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1068 begin_reversible_command (_("select all from range"));
1069 selection->set (touched);
1070 commit_reversible_command ();
1075 Editor::select_all_selectables_using_punch()
1077 Location* location = session->locations()->auto_punch_location();
1078 list<Selectable *> touched;
1080 if (location == 0 || (location->end() - location->start() <= 1)) {
1087 if (selection->tracks.empty()) {
1090 ts = &selection->tracks;
1093 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1094 if ((*iter)->hidden()) {
1097 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1099 begin_reversible_command (_("select all from punch"));
1100 selection->set (touched);
1101 commit_reversible_command ();
1106 Editor::select_all_selectables_using_loop()
1108 Location* location = session->locations()->auto_loop_location();
1109 list<Selectable *> touched;
1111 if (location == 0 || (location->end() - location->start() <= 1)) {
1118 if (selection->tracks.empty()) {
1121 ts = &selection->tracks;
1124 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1125 if ((*iter)->hidden()) {
1128 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1130 begin_reversible_command (_("select all from loop"));
1131 selection->set (touched);
1132 commit_reversible_command ();
1137 Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
1141 list<Selectable *> touched;
1144 begin_reversible_command (_("select all after cursor"));
1145 start = cursor->current_frame ;
1146 end = session->current_end_frame();
1148 if (cursor->current_frame > 0) {
1149 begin_reversible_command (_("select all before cursor"));
1151 end = cursor->current_frame - 1;
1160 if (selection->tracks.empty()) {
1163 ts = &selection->tracks;
1166 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1167 if ((*iter)->hidden()) {
1170 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1172 selection->set (touched);
1173 commit_reversible_command ();
1177 Editor::select_all_selectables_using_edit (bool after)
1181 list<Selectable *> touched;
1184 begin_reversible_command (_("select all after edit"));
1185 start = get_preferred_edit_position();
1186 end = session->current_end_frame();
1188 if ((end = get_preferred_edit_position()) > 1) {
1189 begin_reversible_command (_("select all before edit"));
1200 if (selection->tracks.empty()) {
1203 ts = &selection->tracks;
1206 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1207 if ((*iter)->hidden()) {
1210 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1212 selection->set (touched);
1213 commit_reversible_command ();
1217 Editor::select_all_selectables_between (bool within)
1221 list<Selectable *> touched;
1223 if (!get_edit_op_range (start, end)) {
1229 if (selection->tracks.empty()) {
1232 ts = &selection->tracks;
1235 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1236 if ((*iter)->hidden()) {
1239 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1242 selection->set (touched);
1246 Editor::select_range_between ()
1251 if (!get_edit_op_range (start, end)) {
1255 set_mouse_mode (MouseRange);
1256 selection->set ((TimeAxisView*) 0, start, end);
1260 Editor::get_edit_op_range (nframes64_t& start, nframes64_t& end) const
1265 /* in range mode, use any existing selection */
1267 if (mouse_mode == MouseRange && !selection->time.empty()) {
1268 /* we know that these are ordered */
1269 start = selection->time.start();
1270 end = selection->time.end_frame();
1274 if (!mouse_frame (m, ignored)) {
1275 /* mouse is not in a canvas, try playhead+selected marker.
1276 this is probably most true when using menus.
1279 if (selection->markers.empty()) {
1283 start = selection->markers.front()->position();
1284 end = session->audible_frame();
1288 switch (_edit_point) {
1289 case EditAtPlayhead:
1290 if (selection->markers.empty()) {
1291 /* use mouse + playhead */
1293 end = session->audible_frame();
1295 /* use playhead + selected marker */
1296 start = session->audible_frame();
1297 end = selection->markers.front()->position();
1302 /* use mouse + selected marker */
1303 if (selection->markers.empty()) {
1305 end = session->audible_frame();
1307 start = selection->markers.front()->position();
1312 case EditAtSelectedMarker:
1313 /* use mouse + selected marker */
1314 if (selection->markers.empty()) {
1316 MessageDialog win (_("No edit range defined"),
1321 win.set_secondary_text (
1322 _("the edit point is Selected Marker\nbut there is no selected marker."));
1325 win.set_default_response (RESPONSE_CLOSE);
1326 win.set_position (Gtk::WIN_POS_MOUSE);
1331 return false; // NO RANGE
1333 start = selection->markers.front()->position();
1347 /* turn range into one delimited by start...end,
1357 Editor::deselect_all ()
1359 selection->clear ();