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"
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 TrackViewList visible_views;
164 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
165 if ((*i)->marked_for_display()) {
166 visible_views.push_back (*i);
169 selection->set (visible_views);
173 Editor::set_selected_track_as_side_effect (bool force)
175 if (!clicked_trackview) {
179 if (!selection->tracks.empty()) {
181 if (!selection->selected (clicked_trackview)) {
182 selection->add (clicked_trackview);
186 selection->set (clicked_trackview);
191 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
194 case Selection::Toggle:
195 if (selection->selected (&view)) {
197 selection->remove (&view);
200 selection->add (&view);
205 if (!selection->selected (&view)) {
206 selection->add (&view);
211 selection->set (&view);
214 case Selection::Extend:
215 extend_selection_to_track (view);
221 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
223 if (!clicked_trackview) {
231 set_selected_track (*clicked_trackview, op, no_remove);
235 Editor::set_selected_control_point_from_click (Selection::Operation op, bool no_remove)
237 if (!clicked_control_point) {
241 /* select this point and any others that it represents */
246 x1 = pixel_to_frame (clicked_control_point->get_x() - 10);
247 x2 = pixel_to_frame (clicked_control_point->get_x() + 10);
248 y1 = clicked_control_point->get_x() - 10;
249 y2 = clicked_control_point->get_y() + 10;
251 return select_all_within (x1, x2, y1, y2, selection->tracks, op);
255 Editor::get_relevant_audio_tracks (set<AudioTimeAxisView*>& relevant_tracks)
257 /* step one: get all selected tracks and all tracks in the relevant edit groups */
259 for (TrackSelection::iterator ti = selection->tracks.begin(); ti != selection->tracks.end(); ++ti) {
261 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*ti);
267 RouteGroup* group = atv->route()->edit_group();
269 if (group && group->is_active()) {
271 /* active group for this track, loop over all tracks and get every member of the group */
273 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
275 AudioTimeAxisView* tatv;
277 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
279 if (tatv->route()->edit_group() == group) {
280 relevant_tracks.insert (tatv);
285 relevant_tracks.insert (atv);
292 * Call a slot for a given `basis' track and also for any track that is in the same
294 * @param sl Slot to call.
295 * @param basis Basis track.
299 Editor::mapover_audio_tracks (slot<void,AudioTimeAxisView&,uint32_t> sl, TimeAxisView* basis)
301 AudioTimeAxisView* audio_basis = dynamic_cast<AudioTimeAxisView*> (basis);
302 if (audio_basis == 0) {
306 /* work out the tracks that we will call the slot for; use
307 a set here as it will disallow possible duplicates of the
309 set<AudioTimeAxisView*> tracks;
311 /* always call for the basis */
312 tracks.insert (audio_basis);
314 RouteGroup* group = audio_basis->route()->edit_group();
315 if (group && group->is_active()) {
317 /* the basis is a member of an active edit group; find other members */
318 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
319 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*> (*i);
320 if (v && v->route()->edit_group() == group) {
327 uint32_t const sz = tracks.size ();
328 for (set<AudioTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
334 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t ignored, RegionView* basis, vector<RegionView*>* all_equivs)
336 boost::shared_ptr<Playlist> pl;
337 vector<boost::shared_ptr<Region> > results;
339 boost::shared_ptr<Diskstream> ds;
341 if ((ds = tv.get_diskstream()) == 0) {
346 if (&tv == &basis->get_time_axis_view()) {
347 /* looking in same track as the original */
351 if ((pl = ds->playlist()) != 0) {
352 pl->get_equivalent_regions (basis->region(), results);
355 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
356 if ((marv = tv.view()->find_view (*ir)) != 0) {
357 all_equivs->push_back (marv);
363 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions)
365 mapover_audio_tracks (bind (mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_trackview());
367 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
369 equivalent_regions.push_back (basis);
373 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool no_track_remove)
375 vector<RegionView*> all_equivalent_regions;
378 if (!clicked_regionview || !clicked_audio_trackview) {
383 button_release_can_deselect = false;
386 if (op == Selection::Toggle || op == Selection::Set) {
390 case Selection::Toggle:
392 if (selection->selected (clicked_regionview)) {
395 /* whatever was clicked was selected already; do nothing here but allow
396 the button release to deselect it
399 button_release_can_deselect = true;
403 if (button_release_can_deselect) {
405 /* just remove this one region, but only on a permitted button release */
407 selection->remove (clicked_regionview);
410 /* no more deselect action on button release till a new press
411 finds an already selected object.
414 button_release_can_deselect = false;
422 if (selection->selected (clicked_audio_trackview)) {
423 get_equivalent_regions (clicked_regionview, all_equivalent_regions);
425 all_equivalent_regions.push_back (clicked_regionview);
428 /* add all the equivalent regions, but only on button press */
432 if (!all_equivalent_regions.empty()) {
436 selection->add (all_equivalent_regions);
442 if (!selection->selected (clicked_regionview)) {
444 get_equivalent_regions (clicked_regionview, all_equivalent_regions);
445 selection->set (all_equivalent_regions);
448 /* no commit necessary: clicked on an already selected region */
458 } else if (op == Selection::Extend) {
460 list<Selectable*> results;
461 nframes64_t last_frame;
462 nframes64_t first_frame;
463 bool same_track = false;
465 /* 1. find the last selected regionview in the track that was clicked in */
468 first_frame = max_frames;
470 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
471 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
473 if ((*x)->region()->last_frame() > last_frame) {
474 last_frame = (*x)->region()->last_frame();
477 if ((*x)->region()->first_frame() < first_frame) {
478 first_frame = (*x)->region()->first_frame();
487 /* 2. figure out the boundaries for our search for new objects */
489 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
491 if (last_frame < clicked_regionview->region()->first_frame()) {
492 first_frame = last_frame;
493 last_frame = clicked_regionview->region()->last_frame();
495 last_frame = first_frame;
496 first_frame = clicked_regionview->region()->first_frame();
500 case OverlapExternal:
501 if (last_frame < clicked_regionview->region()->first_frame()) {
502 first_frame = last_frame;
503 last_frame = clicked_regionview->region()->last_frame();
505 last_frame = first_frame;
506 first_frame = clicked_regionview->region()->first_frame();
510 case OverlapInternal:
511 if (last_frame < clicked_regionview->region()->first_frame()) {
512 first_frame = last_frame;
513 last_frame = clicked_regionview->region()->last_frame();
515 last_frame = first_frame;
516 first_frame = clicked_regionview->region()->first_frame();
522 /* nothing to do except add clicked region to selection, since it
523 overlaps with the existing selection in this track.
530 /* click in a track that has no regions selected, so extend vertically
531 to pick out all regions that are defined by the existing selection
536 first_frame = entered_regionview->region()->position();
537 last_frame = entered_regionview->region()->last_frame();
539 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
540 if ((*i)->region()->position() < first_frame) {
541 first_frame = (*i)->region()->position();
543 if ((*i)->region()->last_frame() + 1 > last_frame) {
544 last_frame = (*i)->region()->last_frame();
549 /* 2. find all the tracks we should select in */
551 set<AudioTimeAxisView*> relevant_tracks;
552 set<AudioTimeAxisView*> already_in_selection;
554 get_relevant_audio_tracks (relevant_tracks);
556 if (relevant_tracks.empty()) {
558 /* no relevant tracks -> no tracks selected .. thus .. if
559 the regionview we're in isn't selected (i.e. we're
560 about to extend to it), then find all tracks between
561 the this one and any selected ones.
564 if (!selection->selected (entered_regionview)) {
566 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&entered_regionview->get_time_axis_view());
570 /* add this track to the ones we will search */
572 relevant_tracks.insert (atv);
574 /* find the track closest to this one that
575 already a selected region.
578 AudioTimeAxisView* closest = 0;
579 int distance = INT_MAX;
580 int key = atv->route()->order_key ("editor");
582 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
584 AudioTimeAxisView* aatv = dynamic_cast<AudioTimeAxisView*>(&(*x)->get_time_axis_view());
586 if (aatv && aatv != atv) {
588 pair<set<AudioTimeAxisView*>::iterator,bool> result;
590 result = already_in_selection.insert (aatv);
593 /* newly added to already_in_selection */
596 int d = aatv->route()->order_key ("editor");
600 if (abs (d) < distance) {
610 /* now add all tracks between that one and this one */
612 int okey = closest->route()->order_key ("editor");
618 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
619 AudioTimeAxisView* aatv = dynamic_cast<AudioTimeAxisView*>(*x);
620 if (aatv && aatv != atv) {
622 int k = aatv->route()->order_key ("editor");
624 if (k >= okey && k <= key) {
626 /* in range but don't add it if
627 it already has tracks selected.
628 this avoids odd selection
629 behaviour that feels wrong.
632 if (find (already_in_selection.begin(),
633 already_in_selection.end(),
634 aatv) == already_in_selection.end()) {
636 relevant_tracks.insert (aatv);
646 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
647 one that was clicked.
650 for (set<AudioTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
651 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
654 /* 4. convert to a vector of audio regions */
656 vector<RegionView*> regions;
658 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
661 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
662 regions.push_back (arv);
666 if (!regions.empty()) {
667 selection->add (regions);
678 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
680 vector<RegionView*> all_equivalent_regions;
682 get_regions_corresponding_to (region, all_equivalent_regions);
684 if (all_equivalent_regions.empty()) {
689 case Selection::Toggle:
690 /* XXX this is not correct */
691 selection->toggle (all_equivalent_regions);
694 selection->set (all_equivalent_regions);
696 case Selection::Extend:
697 selection->add (all_equivalent_regions);
700 selection->add (all_equivalent_regions);
706 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, boost::weak_ptr<Region> weak_r)
709 boost::shared_ptr<Region> r (weak_r.lock());
715 boost::shared_ptr<AudioRegion> ar;
717 if ((ar = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
721 if ((rv = sv->find_view (ar)) == 0) {
725 /* don't reset the selection if its something other than
726 a single other region.
729 if (selection->regions.size() > 1) {
733 begin_reversible_command (_("set selected regions"));
737 commit_reversible_command () ;
743 Editor::track_selection_changed ()
745 switch (selection->tracks.size()){
749 set_selected_mixer_strip (*(selection->tracks.front()));
753 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
754 if (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end()) {
755 (*i)->set_selected (true);
757 (*i)->set_selected (false);
761 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
765 Editor::time_selection_changed ()
767 if (Profile->get_sae()) {
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::sensitize_the_right_region_actions (bool have_selected_regions)
796 for (vector<Glib::RefPtr<Action> >::iterator x = ActionManager::region_selection_sensitive_actions.begin();
797 x != ActionManager::region_selection_sensitive_actions.end(); ++x) {
799 string accel_path = (*x)->get_accel_path ();
802 /* if there is an accelerator, it should always be sensitive
803 to allow for keyboard ops on entered regions.
806 bool known = ActionManager::lookup_entry (accel_path, key);
808 if (known && ((key.get_key() != GDK_VoidSymbol) && (key.get_key() != 0))) {
809 (*x)->set_sensitive (true);
811 (*x)->set_sensitive (have_selected_regions);
818 Editor::region_selection_changed ()
820 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
821 (*i)->set_selected_regionviews (selection->regions);
824 sensitize_the_right_region_actions (!selection->regions.empty());
826 zoomed_to_region = false;
830 Editor::point_selection_changed ()
832 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
833 (*i)->set_selected_points (selection->points);
838 Editor::select_all_in_track (Selection::Operation op)
840 list<Selectable *> touched;
842 if (!clicked_trackview) {
846 clicked_trackview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
849 case Selection::Toggle:
850 selection->add (touched);
853 selection->set (touched);
855 case Selection::Extend:
856 /* meaningless, because we're selecting everything */
859 selection->add (touched);
865 Editor::select_all (Selection::Operation op)
867 list<Selectable *> touched;
869 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
870 if ((*iter)->hidden()) {
873 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
875 begin_reversible_command (_("select all"));
878 selection->add (touched);
880 case Selection::Toggle:
881 selection->add (touched);
884 selection->set (touched);
886 case Selection::Extend:
887 /* meaningless, because we're selecting everything */
890 commit_reversible_command ();
894 Editor::invert_selection_in_track ()
896 list<Selectable *> touched;
898 if (!clicked_trackview) {
902 clicked_trackview->get_inverted_selectables (*selection, touched);
903 selection->set (touched);
907 Editor::invert_selection ()
909 list<Selectable *> touched;
911 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
912 if ((*iter)->hidden()) {
915 (*iter)->get_inverted_selectables (*selection, touched);
918 selection->set (touched);
922 Editor::select_all_within (nframes64_t start, nframes64_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op)
924 list<Selectable*> touched;
925 list<Selectable*>::size_type n = 0;
926 TrackViewList touched_tracks;
928 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
929 if ((*iter)->hidden()) {
935 (*iter)->get_selectables (start, end, top, bot, touched);
937 if (n != touched.size()) {
938 touched_tracks.push_back (*iter);
942 if (touched.empty()) {
946 if (!touched_tracks.empty()) {
950 selection->add (touched_tracks);
952 case Selection::Toggle:
953 selection->toggle (touched_tracks);
956 selection->set (touched_tracks);
958 case Selection::Extend:
959 /* not defined yet */
964 begin_reversible_command (_("select all within"));
967 selection->add (touched);
969 case Selection::Toggle:
970 selection->toggle (touched);
973 selection->set (touched);
975 case Selection::Extend:
976 /* not defined yet */
980 commit_reversible_command ();
982 return !touched.empty();
986 Editor::set_selection_from_audio_region ()
988 if (selection->regions.empty()) {
992 selection->set (0, selection->regions.start(), selection->regions.end_frame());
993 if (!Profile->get_sae()) {
994 set_mouse_mode (Editing::MouseRange, false);
999 Editor::set_selection_from_punch()
1003 if ((location = session->locations()->auto_punch_location()) == 0) {
1007 set_selection_from_range (*location);
1011 Editor::set_selection_from_loop()
1015 if ((location = session->locations()->auto_loop_location()) == 0) {
1018 set_selection_from_range (*location);
1022 Editor::set_selection_from_range (Location& loc)
1024 begin_reversible_command (_("set selection from range"));
1025 selection->set (0, loc.start(), loc.end());
1026 commit_reversible_command ();
1028 if (!Profile->get_sae()) {
1029 set_mouse_mode (Editing::MouseRange, false);
1034 Editor::select_all_selectables_using_time_selection ()
1036 list<Selectable *> touched;
1038 if (selection->time.empty()) {
1042 nframes64_t start = selection->time[clicked_selection].start;
1043 nframes64_t end = selection->time[clicked_selection].end;
1045 if (end - start < 1) {
1051 if (selection->tracks.empty()) {
1054 ts = &selection->tracks;
1057 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1058 if ((*iter)->hidden()) {
1061 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1064 begin_reversible_command (_("select all from range"));
1065 selection->set (touched);
1066 commit_reversible_command ();
1071 Editor::select_all_selectables_using_punch()
1073 Location* location = session->locations()->auto_punch_location();
1074 list<Selectable *> touched;
1076 if (location == 0 || (location->end() - location->start() <= 1)) {
1083 if (selection->tracks.empty()) {
1086 ts = &selection->tracks;
1089 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1090 if ((*iter)->hidden()) {
1093 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1095 begin_reversible_command (_("select all from punch"));
1096 selection->set (touched);
1097 commit_reversible_command ();
1102 Editor::select_all_selectables_using_loop()
1104 Location* location = session->locations()->auto_loop_location();
1105 list<Selectable *> touched;
1107 if (location == 0 || (location->end() - location->start() <= 1)) {
1114 if (selection->tracks.empty()) {
1117 ts = &selection->tracks;
1120 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1121 if ((*iter)->hidden()) {
1124 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1126 begin_reversible_command (_("select all from loop"));
1127 selection->set (touched);
1128 commit_reversible_command ();
1133 Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
1137 list<Selectable *> touched;
1140 begin_reversible_command (_("select all after cursor"));
1141 start = cursor->current_frame ;
1142 end = session->current_end_frame();
1144 if (cursor->current_frame > 0) {
1145 begin_reversible_command (_("select all before cursor"));
1147 end = cursor->current_frame - 1;
1156 if (selection->tracks.empty()) {
1159 ts = &selection->tracks;
1162 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1163 if ((*iter)->hidden()) {
1166 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1168 selection->set (touched);
1169 commit_reversible_command ();
1173 Editor::select_all_selectables_using_edit (bool after)
1177 list<Selectable *> touched;
1180 begin_reversible_command (_("select all after edit"));
1181 start = get_preferred_edit_position();
1182 end = session->current_end_frame();
1184 if ((end = get_preferred_edit_position()) > 1) {
1185 begin_reversible_command (_("select all before edit"));
1196 if (selection->tracks.empty()) {
1199 ts = &selection->tracks;
1202 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1203 if ((*iter)->hidden()) {
1206 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1208 selection->set (touched);
1209 commit_reversible_command ();
1213 Editor::select_all_selectables_between (bool within)
1217 list<Selectable *> touched;
1219 if (!get_edit_op_range (start, end)) {
1225 if (selection->tracks.empty()) {
1228 ts = &selection->tracks;
1231 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1232 if ((*iter)->hidden()) {
1235 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1238 selection->set (touched);
1242 Editor::select_range_between ()
1247 if (!get_edit_op_range (start, end)) {
1251 set_mouse_mode (MouseRange);
1252 selection->set ((TimeAxisView*) 0, start, end);
1256 Editor::get_edit_op_range (nframes64_t& start, nframes64_t& end) const
1261 /* in range mode, use any existing selection */
1263 if (mouse_mode == MouseRange && !selection->time.empty()) {
1264 /* we know that these are ordered */
1265 start = selection->time.start();
1266 end = selection->time.end_frame();
1270 if (!mouse_frame (m, ignored)) {
1271 /* mouse is not in a canvas, try playhead+selected marker.
1272 this is probably most true when using menus.
1275 if (selection->markers.empty()) {
1279 start = selection->markers.front()->position();
1280 end = session->audible_frame();
1284 switch (_edit_point) {
1285 case EditAtPlayhead:
1286 if (selection->markers.empty()) {
1287 /* use mouse + playhead */
1289 end = session->audible_frame();
1291 /* use playhead + selected marker */
1292 start = session->audible_frame();
1293 end = selection->markers.front()->position();
1298 /* use mouse + selected marker */
1299 if (selection->markers.empty()) {
1301 end = session->audible_frame();
1303 start = selection->markers.front()->position();
1308 case EditAtSelectedMarker:
1309 /* use mouse + selected marker */
1310 if (selection->markers.empty()) {
1312 MessageDialog win (_("No edit range defined"),
1317 win.set_secondary_text (
1318 _("the edit point is Selected Marker\nbut there is no selected marker."));
1321 win.set_default_response (RESPONSE_CLOSE);
1322 win.set_position (Gtk::WIN_POS_MOUSE);
1327 return false; // NO RANGE
1329 start = selection->markers.front()->position();
1343 /* turn range into one delimited by start...end,
1353 Editor::deselect_all ()
1355 selection->clear ();