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 selection->set (track_views);
167 Editor::set_selected_track_as_side_effect (bool force)
169 if (!clicked_trackview) {
173 if (!selection->tracks.empty()) {
174 if (!selection->selected (clicked_trackview)) {
175 selection->add (clicked_trackview);
179 selection->set (clicked_trackview);
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_trackview) {
238 set_selected_track (*clicked_trackview, 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_audio_tracks (set<AudioTimeAxisView*>& 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 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*ti);
274 RouteGroup* group = atv->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 AudioTimeAxisView* tatv;
284 if ((tatv = dynamic_cast<AudioTimeAxisView*> (*i)) != 0) {
286 if (tatv->route()->edit_group() == group) {
287 relevant_tracks.insert (tatv);
292 relevant_tracks.insert (atv);
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_audio_tracks (slot<void,AudioTimeAxisView&,uint32_t> sl, TimeAxisView* basis)
308 AudioTimeAxisView* audio_basis = dynamic_cast<AudioTimeAxisView*> (basis);
309 if (audio_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<AudioTimeAxisView*> tracks;
318 /* always call for the basis */
319 tracks.insert (audio_basis);
321 RouteGroup* group = audio_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::iterator i = track_views.begin(); i != track_views.end(); ++i) {
326 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*> (*i);
327 if (v && v->route()->edit_group() == group) {
334 uint32_t const sz = tracks.size ();
335 for (set<AudioTimeAxisView*>::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)
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)
372 mapover_audio_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_audio_trackview) {
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_audio_trackview)) {
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)) {
451 get_equivalent_regions (clicked_regionview, all_equivalent_regions);
452 selection->set (all_equivalent_regions);
455 /* no commit necessary: clicked on an already selected region */
465 } else if (op == Selection::Extend) {
467 list<Selectable*> results;
468 nframes_t last_frame;
469 nframes_t first_frame;
470 bool same_track = false;
472 /* 1. find the last selected regionview in the track that was clicked in */
475 first_frame = max_frames;
477 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
478 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
480 if ((*x)->region()->last_frame() > last_frame) {
481 last_frame = (*x)->region()->last_frame();
484 if ((*x)->region()->first_frame() < first_frame) {
485 first_frame = (*x)->region()->first_frame();
494 /* 2. figure out the boundaries for our search for new objects */
496 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
498 if (last_frame < clicked_regionview->region()->first_frame()) {
499 first_frame = last_frame;
500 last_frame = clicked_regionview->region()->last_frame();
502 last_frame = first_frame;
503 first_frame = clicked_regionview->region()->first_frame();
507 case OverlapExternal:
508 if (last_frame < clicked_regionview->region()->first_frame()) {
509 first_frame = last_frame;
510 last_frame = clicked_regionview->region()->last_frame();
512 last_frame = first_frame;
513 first_frame = clicked_regionview->region()->first_frame();
517 case OverlapInternal:
518 if (last_frame < clicked_regionview->region()->first_frame()) {
519 first_frame = last_frame;
520 last_frame = clicked_regionview->region()->last_frame();
522 last_frame = first_frame;
523 first_frame = clicked_regionview->region()->first_frame();
529 /* nothing to do except add clicked region to selection, since it
530 overlaps with the existing selection in this track.
537 /* click in a track that has no regions selected, so extend vertically
538 to pick out all regions that are defined by the existing selection
543 first_frame = entered_regionview->region()->position();
544 last_frame = entered_regionview->region()->last_frame();
546 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
547 if ((*i)->region()->position() < first_frame) {
548 first_frame = (*i)->region()->position();
550 if ((*i)->region()->last_frame() + 1 > last_frame) {
551 last_frame = (*i)->region()->last_frame();
556 /* 2. find all the tracks we should select in */
558 set<AudioTimeAxisView*> relevant_tracks;
559 set<AudioTimeAxisView*> already_in_selection;
561 get_relevant_audio_tracks (relevant_tracks);
563 if (relevant_tracks.empty()) {
565 /* no relevant tracks -> no tracks selected .. thus .. if
566 the regionview we're in isn't selected (i.e. we're
567 about to extend to it), then find all tracks between
568 the this one and any selected ones.
571 if (!selection->selected (entered_regionview)) {
573 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&entered_regionview->get_time_axis_view());
577 /* add this track to the ones we will search */
579 relevant_tracks.insert (atv);
581 /* find the track closest to this one that
582 already a selected region.
585 AudioTimeAxisView* closest = 0;
586 int distance = INT_MAX;
587 int key = atv->route()->order_key ("editor");
589 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
591 AudioTimeAxisView* aatv = dynamic_cast<AudioTimeAxisView*>(&(*x)->get_time_axis_view());
593 if (aatv && aatv != atv) {
595 pair<set<AudioTimeAxisView*>::iterator,bool> result;
597 result = already_in_selection.insert (aatv);
600 /* newly added to already_in_selection */
603 int d = aatv->route()->order_key ("editor");
607 if (abs (d) < distance) {
617 /* now add all tracks between that one and this one */
619 int okey = closest->route()->order_key ("editor");
625 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
626 AudioTimeAxisView* aatv = dynamic_cast<AudioTimeAxisView*>(*x);
627 if (aatv && aatv != atv) {
629 int k = aatv->route()->order_key ("editor");
631 if (k >= okey && k <= key) {
633 /* in range but don't add it if
634 it already has tracks selected.
635 this avoids odd selection
636 behaviour that feels wrong.
639 if (find (already_in_selection.begin(),
640 already_in_selection.end(),
641 aatv) == already_in_selection.end()) {
643 relevant_tracks.insert (aatv);
653 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
654 one that was clicked.
657 for (set<AudioTimeAxisView*>::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 audio 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()) {
696 case Selection::Toggle:
697 /* XXX this is not correct */
698 selection->toggle (all_equivalent_regions);
701 selection->set (all_equivalent_regions);
703 case Selection::Extend:
704 selection->add (all_equivalent_regions);
707 selection->add (all_equivalent_regions);
713 Editor::set_selected_regionview_from_map_event (GdkEventAny* ev, StreamView* sv, boost::weak_ptr<Region> weak_r)
716 boost::shared_ptr<Region> r (weak_r.lock());
722 boost::shared_ptr<AudioRegion> ar;
724 if ((ar = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
728 if ((rv = sv->find_view (ar)) == 0) {
732 /* don't reset the selection if its something other than
733 a single other region.
736 if (selection->regions.size() > 1) {
740 begin_reversible_command (_("set selected regions"));
744 commit_reversible_command () ;
750 Editor::track_selection_changed ()
752 switch (selection->tracks.size()){
756 set_selected_mixer_strip (*(selection->tracks.front()));
760 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
761 if (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end()) {
762 (*i)->set_selected (true);
764 (*i)->set_selected (false);
768 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
772 Editor::time_selection_changed ()
774 if (Profile->get_sae()) {
778 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
779 (*i)->hide_selection ();
782 if (selection->tracks.empty()) {
783 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
784 (*i)->show_selection (selection->time);
787 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
788 (*i)->show_selection (selection->time);
792 if (selection->time.empty()) {
793 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
795 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
801 Editor::sensitize_the_right_region_actions (bool have_selected_regions)
803 for (vector<Glib::RefPtr<Action> >::iterator x = ActionManager::region_selection_sensitive_actions.begin();
804 x != ActionManager::region_selection_sensitive_actions.end(); ++x) {
806 string accel_path = (*x)->get_accel_path ();
809 /* if there is an accelerator, it should always be sensitive
810 to allow for keyboard ops on entered regions.
813 bool known = ActionManager::lookup_entry (accel_path, key);
815 if (known && ((key.get_key() != GDK_VoidSymbol) && (key.get_key() != 0))) {
816 (*x)->set_sensitive (true);
818 (*x)->set_sensitive (have_selected_regions);
825 Editor::region_selection_changed ()
827 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
828 (*i)->set_selected_regionviews (selection->regions);
831 sensitize_the_right_region_actions (!selection->regions.empty());
833 zoomed_to_region = false;
837 Editor::point_selection_changed ()
839 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
840 (*i)->set_selected_points (selection->points);
845 Editor::select_all_in_track (Selection::Operation op)
847 list<Selectable *> touched;
849 if (!clicked_trackview) {
853 clicked_trackview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
856 case Selection::Toggle:
857 selection->add (touched);
860 selection->set (touched);
862 case Selection::Extend:
863 /* meaningless, because we're selecting everything */
866 selection->add (touched);
872 Editor::select_all (Selection::Operation op)
874 list<Selectable *> touched;
876 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
877 if ((*iter)->hidden()) {
880 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
882 begin_reversible_command (_("select all"));
885 selection->add (touched);
887 case Selection::Toggle:
888 selection->add (touched);
891 selection->set (touched);
893 case Selection::Extend:
894 /* meaningless, because we're selecting everything */
897 commit_reversible_command ();
901 Editor::invert_selection_in_track ()
903 list<Selectable *> touched;
905 if (!clicked_trackview) {
909 clicked_trackview->get_inverted_selectables (*selection, touched);
910 selection->set (touched);
914 Editor::invert_selection ()
916 list<Selectable *> touched;
918 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
919 if ((*iter)->hidden()) {
922 (*iter)->get_inverted_selectables (*selection, touched);
925 selection->set (touched);
929 Editor::select_all_within (nframes_t start, nframes_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op)
931 list<Selectable*> touched;
932 list<Selectable*>::size_type n = 0;
933 TrackViewList touched_tracks;
935 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
936 if ((*iter)->hidden()) {
942 (*iter)->get_selectables (start, end, top, bot, touched);
944 if (n != touched.size()) {
945 touched_tracks.push_back (*iter);
949 if (touched.empty()) {
953 if (!touched_tracks.empty()) {
957 selection->add (touched_tracks);
959 case Selection::Toggle:
960 selection->toggle (touched_tracks);
963 selection->set (touched_tracks);
965 case Selection::Extend:
966 /* not defined yet */
971 begin_reversible_command (_("select all within"));
974 selection->add (touched);
976 case Selection::Toggle:
977 selection->toggle (touched);
980 selection->set (touched);
982 case Selection::Extend:
983 /* not defined yet */
987 commit_reversible_command ();
989 return !touched.empty();
993 Editor::set_selection_from_audio_region ()
995 if (selection->regions.empty()) {
999 selection->set (0, selection->regions.start(), selection->regions.end_frame());
1000 if (!Profile->get_sae()) {
1001 set_mouse_mode (Editing::MouseRange, false);
1006 Editor::set_selection_from_punch()
1010 if ((location = session->locations()->auto_punch_location()) == 0) {
1014 set_selection_from_range (*location);
1018 Editor::set_selection_from_loop()
1022 if ((location = session->locations()->auto_loop_location()) == 0) {
1025 set_selection_from_range (*location);
1029 Editor::set_selection_from_range (Location& loc)
1031 begin_reversible_command (_("set selection from range"));
1032 selection->set (0, loc.start(), loc.end());
1033 commit_reversible_command ();
1035 if (!Profile->get_sae()) {
1036 set_mouse_mode (Editing::MouseRange, false);
1041 Editor::select_all_selectables_using_time_selection ()
1043 list<Selectable *> touched;
1045 if (selection->time.empty()) {
1049 nframes_t start = selection->time[clicked_selection].start;
1050 nframes_t end = selection->time[clicked_selection].end;
1052 if (end - start < 1) {
1058 if (selection->tracks.empty()) {
1061 ts = &selection->tracks;
1064 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1065 if ((*iter)->hidden()) {
1068 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1071 begin_reversible_command (_("select all from range"));
1072 selection->set (touched);
1073 commit_reversible_command ();
1078 Editor::select_all_selectables_using_punch()
1080 Location* location = session->locations()->auto_punch_location();
1081 list<Selectable *> touched;
1083 if (location == 0 || (location->end() - location->start() <= 1)) {
1090 if (selection->tracks.empty()) {
1093 ts = &selection->tracks;
1096 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1097 if ((*iter)->hidden()) {
1100 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1102 begin_reversible_command (_("select all from punch"));
1103 selection->set (touched);
1104 commit_reversible_command ();
1109 Editor::select_all_selectables_using_loop()
1111 Location* location = session->locations()->auto_loop_location();
1112 list<Selectable *> touched;
1114 if (location == 0 || (location->end() - location->start() <= 1)) {
1121 if (selection->tracks.empty()) {
1124 ts = &selection->tracks;
1127 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1128 if ((*iter)->hidden()) {
1131 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1133 begin_reversible_command (_("select all from loop"));
1134 selection->set (touched);
1135 commit_reversible_command ();
1140 Editor::select_all_selectables_using_cursor (Cursor *cursor, bool after)
1144 list<Selectable *> touched;
1147 begin_reversible_command (_("select all after cursor"));
1148 start = cursor->current_frame ;
1149 end = session->current_end_frame();
1151 if (cursor->current_frame > 0) {
1152 begin_reversible_command (_("select all before cursor"));
1154 end = cursor->current_frame - 1;
1163 if (selection->tracks.empty()) {
1166 ts = &selection->tracks;
1169 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1170 if ((*iter)->hidden()) {
1173 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1175 selection->set (touched);
1176 commit_reversible_command ();
1180 Editor::select_all_selectables_using_edit (bool after)
1184 list<Selectable *> touched;
1187 begin_reversible_command (_("select all after edit"));
1188 start = get_preferred_edit_position();
1189 end = session->current_end_frame();
1191 if ((end = get_preferred_edit_position()) > 1) {
1192 begin_reversible_command (_("select all before edit"));
1203 if (selection->tracks.empty()) {
1206 ts = &selection->tracks;
1209 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1210 if ((*iter)->hidden()) {
1213 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1215 selection->set (touched);
1216 commit_reversible_command ();
1220 Editor::select_all_selectables_between (bool within)
1224 list<Selectable *> touched;
1226 if (!get_edit_op_range (start, end)) {
1232 if (selection->tracks.empty()) {
1235 ts = &selection->tracks;
1238 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1239 if ((*iter)->hidden()) {
1242 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1245 selection->set (touched);
1249 Editor::select_range_between ()
1254 if (!get_edit_op_range (start, end)) {
1258 set_mouse_mode (MouseRange);
1259 selection->set ((TimeAxisView*) 0, start, end);
1263 Editor::get_edit_op_range (nframes64_t& start, nframes64_t& end) const
1268 /* in range mode, use any existing selection */
1270 if (mouse_mode == MouseRange && !selection->time.empty()) {
1271 /* we know that these are ordered */
1272 start = selection->time.start();
1273 end = selection->time.end_frame();
1277 if (!mouse_frame (m, ignored)) {
1278 /* mouse is not in a canvas, try playhead+selected marker.
1279 this is probably most true when using menus.
1282 if (selection->markers.empty()) {
1286 start = selection->markers.front()->position();
1287 end = session->audible_frame();
1291 switch (_edit_point) {
1292 case EditAtPlayhead:
1293 if (selection->markers.empty()) {
1294 /* use mouse + playhead */
1296 end = session->audible_frame();
1298 /* use playhead + selected marker */
1299 start = session->audible_frame();
1300 end = selection->markers.front()->position();
1305 /* use mouse + selected marker */
1306 if (selection->markers.empty()) {
1308 end = session->audible_frame();
1310 start = selection->markers.front()->position();
1315 case EditAtSelectedMarker:
1316 /* use mouse + selected marker */
1317 if (selection->markers.empty()) {
1319 MessageDialog win (_("No edit range defined"),
1324 win.set_secondary_text (
1325 _("the edit point is Selected Marker\nbut there is no selected marker."));
1328 win.set_default_response (RESPONSE_CLOSE);
1329 win.set_position (Gtk::WIN_POS_MOUSE);
1334 return false; // NO RANGE
1336 start = selection->markers.front()->position();
1354 Editor::deselect_all ()
1356 selection->clear ();