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/session.h"
26 #include "ardour/diskstream.h"
27 #include "ardour/playlist.h"
28 #include "ardour/route_group.h"
29 #include "ardour/profile.h"
33 #include "audio_time_axis.h"
34 #include "audio_region_view.h"
35 #include "audio_streamview.h"
36 #include "automation_line.h"
37 #include "control_point.h"
38 #include "editor_regions.h"
43 using namespace ARDOUR;
47 using namespace Gtkmm2ext;
48 using namespace Editing;
50 struct TrackViewByPositionSorter
52 bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
53 return a->y_position() < b->y_position();
58 Editor::extend_selection_to_track (TimeAxisView& view)
60 if (selection->selected (&view)) {
61 /* already selected, do nothing */
65 if (selection->tracks.empty()) {
67 if (!selection->selected (&view)) {
68 selection->set (&view);
75 /* something is already selected, so figure out which range of things to add */
77 TrackViewList to_be_added;
78 TrackViewList sorted = track_views;
79 TrackViewByPositionSorter cmp;
80 bool passed_clicked = false;
85 if (!selection->selected (&view)) {
86 to_be_added.push_back (&view);
89 /* figure out if we should go forward or backwards */
91 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
94 passed_clicked = true;
97 if (selection->selected (*i)) {
107 passed_clicked = false;
111 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
114 passed_clicked = true;
118 if (passed_clicked) {
119 if ((*i)->hidden()) {
122 if (selection->selected (*i)) {
124 } else if (!(*i)->hidden()) {
125 to_be_added.push_back (*i);
132 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
135 passed_clicked = true;
139 if (passed_clicked) {
141 if ((*r)->hidden()) {
145 if (selection->selected (*r)) {
147 } else if (!(*r)->hidden()) {
148 to_be_added.push_back (*r);
154 if (!to_be_added.empty()) {
155 selection->add (to_be_added);
163 Editor::select_all_tracks ()
165 TrackViewList visible_views;
166 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
167 if ((*i)->marked_for_display()) {
168 visible_views.push_back (*i);
171 selection->set (visible_views);
175 Editor::set_selected_track_as_side_effect (bool force)
177 if (!clicked_routeview) {
181 if (!selection->tracks.empty()) {
182 if (!selection->selected (clicked_routeview)) {
183 selection->add (clicked_routeview);
187 selection->set (clicked_routeview);
192 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
195 case Selection::Toggle:
196 if (selection->selected (&view)) {
198 selection->remove (&view);
201 selection->add (&view);
206 if (!selection->selected (&view)) {
207 selection->add (&view);
212 selection->set (&view);
215 case Selection::Extend:
216 extend_selection_to_track (view);
222 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
224 if (!clicked_routeview) {
232 set_selected_track (*clicked_routeview, op, no_remove);
236 Editor::set_selected_control_point_from_click (Selection::Operation op, bool /*no_remove*/)
238 if (!clicked_control_point) {
242 /* select this point and any others that it represents */
247 x1 = pixel_to_frame (clicked_control_point->get_x() - 10);
248 x2 = pixel_to_frame (clicked_control_point->get_x() + 10);
249 y1 = clicked_control_point->get_x() - 10;
250 y2 = clicked_control_point->get_y() + 10;
252 return select_all_within (x1, x2, y1, y2, selection->tracks, op);
256 Editor::get_onscreen_tracks (TrackViewList& tvl)
258 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
259 if ((*i)->y_position() < _canvas_height) {
265 /** Call a slot for a given `basis' track and also for any track that is in the same
266 * active route group with a particular set of properties.
268 * @param sl Slot to call.
269 * @param basis Basis track.
270 * @param prop Properties that active edit groups must share to be included in the map.
274 Editor::mapover_tracks (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, RouteGroup::Property prop) const
276 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
277 if (route_basis == 0) {
281 set<RouteTimeAxisView*> tracks;
282 tracks.insert (route_basis);
284 RouteGroup* group = route_basis->route()->route_group();
285 if (group && group->active_property (prop)) {
287 /* the basis is a member of an active route group, with the appropriate
288 properties; find other members */
290 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
291 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
292 if (v && v->route()->route_group() == group) {
299 uint32_t const sz = tracks.size ();
300 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
306 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
308 boost::shared_ptr<Playlist> pl;
309 vector<boost::shared_ptr<Region> > results;
311 boost::shared_ptr<Diskstream> ds;
313 if ((ds = tv.get_diskstream()) == 0) {
318 if (&tv == &basis->get_time_axis_view()) {
319 /* looking in same track as the original */
323 if ((pl = ds->playlist()) != 0) {
324 pl->get_equivalent_regions (basis->region(), results);
327 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
328 if ((marv = tv.view()->find_view (*ir)) != 0) {
329 all_equivs->push_back (marv);
335 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, RouteGroup::Property prop) const
337 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_trackview(), prop);
339 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
341 equivalent_regions.push_back (basis);
345 Editor::get_equivalent_regions (RegionSelection & basis, RouteGroup::Property prop) const
347 RegionSelection equivalent;
349 for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
351 vector<RegionView*> eq;
354 sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
355 &(*i)->get_trackview(), prop
358 for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
370 Editor::get_regionview_count_from_region_list (boost::shared_ptr<Region> region)
372 int region_count = 0;
374 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
376 RouteTimeAxisView* tatv;
378 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
380 boost::shared_ptr<Playlist> pl;
381 vector<boost::shared_ptr<Region> > results;
383 boost::shared_ptr<Diskstream> ds;
385 if ((ds = tatv->get_diskstream()) == 0) {
390 if ((pl = (ds->playlist())) != 0) {
391 pl->get_region_list_equivalent_regions (region, results);
394 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
395 if ((marv = tatv->view()->find_view (*ir)) != 0) {
408 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool /*no_track_remove*/)
410 vector<RegionView*> all_equivalent_regions;
413 if (!clicked_regionview || !clicked_routeview) {
418 button_release_can_deselect = false;
421 if (op == Selection::Toggle || op == Selection::Set) {
425 case Selection::Toggle:
427 if (selection->selected (clicked_regionview)) {
430 /* whatever was clicked was selected already; do nothing here but allow
431 the button release to deselect it
434 button_release_can_deselect = true;
438 if (button_release_can_deselect) {
440 /* just remove this one region, but only on a permitted button release */
442 selection->remove (clicked_regionview);
445 /* no more deselect action on button release till a new press
446 finds an already selected object.
449 button_release_can_deselect = false;
457 if (selection->selected (clicked_routeview)) {
458 get_equivalent_regions (clicked_regionview, all_equivalent_regions, RouteGroup::Select);
460 all_equivalent_regions.push_back (clicked_regionview);
463 /* add all the equivalent regions, but only on button press */
465 if (!all_equivalent_regions.empty()) {
469 selection->add (all_equivalent_regions);
475 if (!selection->selected (clicked_regionview)) {
476 get_equivalent_regions (clicked_regionview, all_equivalent_regions, RouteGroup::Select);
477 selection->set (all_equivalent_regions);
480 /* no commit necessary: clicked on an already selected region */
490 } else if (op == Selection::Extend) {
492 list<Selectable*> results;
493 nframes64_t last_frame;
494 nframes64_t first_frame;
495 bool same_track = false;
497 /* 1. find the last selected regionview in the track that was clicked in */
500 first_frame = max_frames;
502 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
503 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
505 if ((*x)->region()->last_frame() > last_frame) {
506 last_frame = (*x)->region()->last_frame();
509 if ((*x)->region()->first_frame() < first_frame) {
510 first_frame = (*x)->region()->first_frame();
519 /* 2. figure out the boundaries for our search for new objects */
521 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
523 if (last_frame < clicked_regionview->region()->first_frame()) {
524 first_frame = last_frame;
525 last_frame = clicked_regionview->region()->last_frame();
527 last_frame = first_frame;
528 first_frame = clicked_regionview->region()->first_frame();
532 case OverlapExternal:
533 if (last_frame < clicked_regionview->region()->first_frame()) {
534 first_frame = last_frame;
535 last_frame = clicked_regionview->region()->last_frame();
537 last_frame = first_frame;
538 first_frame = clicked_regionview->region()->first_frame();
542 case OverlapInternal:
543 if (last_frame < clicked_regionview->region()->first_frame()) {
544 first_frame = last_frame;
545 last_frame = clicked_regionview->region()->last_frame();
547 last_frame = first_frame;
548 first_frame = clicked_regionview->region()->first_frame();
554 /* nothing to do except add clicked region to selection, since it
555 overlaps with the existing selection in this track.
562 /* click in a track that has no regions selected, so extend vertically
563 to pick out all regions that are defined by the existing selection
568 first_frame = entered_regionview->region()->position();
569 last_frame = entered_regionview->region()->last_frame();
571 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
572 if ((*i)->region()->position() < first_frame) {
573 first_frame = (*i)->region()->position();
575 if ((*i)->region()->last_frame() + 1 > last_frame) {
576 last_frame = (*i)->region()->last_frame();
581 /* 2. find all the tracks we should select in */
583 set<RouteTimeAxisView*> relevant_tracks;
585 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
586 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
588 relevant_tracks.insert (r);
592 set<RouteTimeAxisView*> already_in_selection;
594 if (relevant_tracks.empty()) {
596 /* no tracks selected .. thus .. if the
597 regionview we're in isn't selected
598 (i.e. we're about to extend to it), then
599 find all tracks between the this one and
603 if (!selection->selected (entered_regionview)) {
605 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&entered_regionview->get_time_axis_view());
609 /* add this track to the ones we will search */
611 relevant_tracks.insert (rtv);
613 /* find the track closest to this one that
614 already a selected region.
617 RouteTimeAxisView* closest = 0;
618 int distance = INT_MAX;
619 int key = rtv->route()->order_key ("editor");
621 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
623 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
625 if (artv && artv != rtv) {
627 pair<set<RouteTimeAxisView*>::iterator,bool> result;
629 result = already_in_selection.insert (artv);
632 /* newly added to already_in_selection */
634 int d = artv->route()->order_key ("editor");
638 if (abs (d) < distance) {
648 /* now add all tracks between that one and this one */
650 int okey = closest->route()->order_key ("editor");
656 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
657 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
658 if (artv && artv != rtv) {
660 int k = artv->route()->order_key ("editor");
662 if (k >= okey && k <= key) {
664 /* in range but don't add it if
665 it already has tracks selected.
666 this avoids odd selection
667 behaviour that feels wrong.
670 if (find (already_in_selection.begin(),
671 already_in_selection.end(),
672 artv) == already_in_selection.end()) {
674 relevant_tracks.insert (artv);
684 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
685 one that was clicked.
688 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
689 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
692 /* 4. convert to a vector of regions */
694 vector<RegionView*> regions;
696 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
699 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
700 regions.push_back (arv);
704 if (!regions.empty()) {
705 selection->add (regions);
716 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
718 vector<RegionView*> all_equivalent_regions;
720 get_regions_corresponding_to (region, all_equivalent_regions);
722 if (all_equivalent_regions.empty()) {
726 begin_reversible_command (_("set selected regions"));
729 case Selection::Toggle:
730 /* XXX this is not correct */
731 selection->toggle (all_equivalent_regions);
734 selection->set (all_equivalent_regions);
736 case Selection::Extend:
737 selection->add (all_equivalent_regions);
740 selection->add (all_equivalent_regions);
744 commit_reversible_command () ;
748 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
751 boost::shared_ptr<Region> r (weak_r.lock());
757 if ((rv = sv->find_view (r)) == 0) {
761 /* don't reset the selection if its something other than
762 a single other region.
765 if (selection->regions.size() > 1) {
769 begin_reversible_command (_("set selected regions"));
773 commit_reversible_command () ;
779 Editor::track_selection_changed ()
781 switch (selection->tracks.size()){
785 set_selected_mixer_strip (*(selection->tracks.front()));
789 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
790 if (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end()) {
791 (*i)->set_selected (true);
793 (*i)->set_selected (false);
797 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
801 Editor::time_selection_changed ()
803 if (Profile->get_sae()) {
807 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
808 (*i)->hide_selection ();
811 if (selection->tracks.empty()) {
812 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
813 (*i)->show_selection (selection->time);
816 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
817 (*i)->show_selection (selection->time);
821 if (selection->time.empty()) {
822 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
824 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
830 Editor::sensitize_the_right_region_actions (bool have_selected_regions)
832 for (vector<Glib::RefPtr<Action> >::iterator x = ActionManager::region_selection_sensitive_actions.begin();
833 x != ActionManager::region_selection_sensitive_actions.end(); ++x) {
835 string accel_path = (*x)->get_accel_path ();
838 /* if there is an accelerator, it should always be sensitive
839 to allow for keyboard ops on entered regions.
842 bool known = ActionManager::lookup_entry (accel_path, key);
844 if (known && ((key.get_key() != GDK_VoidSymbol) && (key.get_key() != 0))) {
845 (*x)->set_sensitive (true);
847 (*x)->set_sensitive (have_selected_regions);
854 Editor::region_selection_changed ()
856 _regions->block_change_connection (true);
857 editor_regions_selection_changed_connection.block(true);
859 _regions->unselect_all ();
861 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
863 (*i)->set_selected_regionviews (selection->regions);
864 _regions->set_selected (selection->regions);
868 sensitize_the_right_region_actions (!selection->regions.empty());
870 _regions->block_change_connection (false);
871 editor_regions_selection_changed_connection.block(false);
875 Editor::point_selection_changed ()
877 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
878 (*i)->set_selected_points (selection->points);
883 Editor::select_all_in_track (Selection::Operation op)
885 list<Selectable *> touched;
887 if (!clicked_routeview) {
891 clicked_routeview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
894 case Selection::Toggle:
895 selection->add (touched);
898 selection->set (touched);
900 case Selection::Extend:
901 /* meaningless, because we're selecting everything */
904 selection->add (touched);
910 Editor::select_all (Selection::Operation op)
912 list<Selectable *> touched;
914 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
915 if ((*iter)->hidden()) {
918 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
920 begin_reversible_command (_("select all"));
923 selection->add (touched);
925 case Selection::Toggle:
926 selection->add (touched);
929 selection->set (touched);
931 case Selection::Extend:
932 /* meaningless, because we're selecting everything */
935 commit_reversible_command ();
938 Editor::invert_selection_in_track ()
940 list<Selectable *> touched;
942 if (!clicked_routeview) {
946 clicked_routeview->get_inverted_selectables (*selection, touched);
947 selection->set (touched);
951 Editor::invert_selection ()
953 list<Selectable *> touched;
955 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
956 if ((*iter)->hidden()) {
959 (*iter)->get_inverted_selectables (*selection, touched);
962 selection->set (touched);
966 Editor::select_all_within (nframes64_t start, nframes64_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op)
968 list<Selectable*> touched;
969 list<Selectable*>::size_type n = 0;
970 TrackViewList touched_tracks;
972 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
973 if ((*iter)->hidden()) {
979 (*iter)->get_selectables (start, end, top, bot, touched);
981 if (n != touched.size()) {
982 touched_tracks.push_back (*iter);
986 if (touched.empty()) {
990 if (!touched_tracks.empty()) {
994 selection->add (touched_tracks);
996 case Selection::Toggle:
997 selection->toggle (touched_tracks);
1000 selection->set (touched_tracks);
1002 case Selection::Extend:
1003 /* not defined yet */
1008 begin_reversible_command (_("select all within"));
1010 case Selection::Add:
1011 selection->add (touched);
1013 case Selection::Toggle:
1014 selection->toggle (touched);
1016 case Selection::Set:
1017 selection->set (touched);
1019 case Selection::Extend:
1020 /* not defined yet */
1024 commit_reversible_command ();
1026 return !touched.empty();
1030 Editor::set_selection_from_region ()
1032 if (selection->regions.empty()) {
1036 selection->set (0, selection->regions.start(), selection->regions.end_frame());
1037 if (!Profile->get_sae()) {
1038 set_mouse_mode (Editing::MouseRange, false);
1043 Editor::set_selection_from_punch()
1047 if ((location = session->locations()->auto_punch_location()) == 0) {
1051 set_selection_from_range (*location);
1055 Editor::set_selection_from_loop()
1059 if ((location = session->locations()->auto_loop_location()) == 0) {
1062 set_selection_from_range (*location);
1066 Editor::set_selection_from_range (Location& loc)
1068 begin_reversible_command (_("set selection from range"));
1069 selection->set (0, loc.start(), loc.end());
1070 commit_reversible_command ();
1072 if (!Profile->get_sae()) {
1073 set_mouse_mode (Editing::MouseRange, false);
1078 Editor::select_all_selectables_using_time_selection ()
1080 list<Selectable *> touched;
1082 if (selection->time.empty()) {
1086 nframes64_t start = selection->time[clicked_selection].start;
1087 nframes64_t end = selection->time[clicked_selection].end;
1089 if (end - start < 1) {
1095 if (selection->tracks.empty()) {
1098 ts = &selection->tracks;
1101 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1102 if ((*iter)->hidden()) {
1105 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1108 begin_reversible_command (_("select all from range"));
1109 selection->set (touched);
1110 commit_reversible_command ();
1115 Editor::select_all_selectables_using_punch()
1117 Location* location = session->locations()->auto_punch_location();
1118 list<Selectable *> touched;
1120 if (location == 0 || (location->end() - location->start() <= 1)) {
1127 if (selection->tracks.empty()) {
1130 ts = &selection->tracks;
1133 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1134 if ((*iter)->hidden()) {
1137 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1139 begin_reversible_command (_("select all from punch"));
1140 selection->set (touched);
1141 commit_reversible_command ();
1146 Editor::select_all_selectables_using_loop()
1148 Location* location = session->locations()->auto_loop_location();
1149 list<Selectable *> touched;
1151 if (location == 0 || (location->end() - location->start() <= 1)) {
1158 if (selection->tracks.empty()) {
1161 ts = &selection->tracks;
1164 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1165 if ((*iter)->hidden()) {
1168 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1170 begin_reversible_command (_("select all from loop"));
1171 selection->set (touched);
1172 commit_reversible_command ();
1177 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1181 list<Selectable *> touched;
1184 begin_reversible_command (_("select all after cursor"));
1185 start = cursor->current_frame ;
1186 end = session->current_end_frame();
1188 if (cursor->current_frame > 0) {
1189 begin_reversible_command (_("select all before cursor"));
1191 end = cursor->current_frame - 1;
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_using_edit (bool after)
1221 list<Selectable *> touched;
1224 begin_reversible_command (_("select all after edit"));
1225 start = get_preferred_edit_position();
1226 end = session->current_end_frame();
1228 if ((end = get_preferred_edit_position()) > 1) {
1229 begin_reversible_command (_("select all before edit"));
1240 if (selection->tracks.empty()) {
1243 ts = &selection->tracks;
1246 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1247 if ((*iter)->hidden()) {
1250 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1252 selection->set (touched);
1253 commit_reversible_command ();
1257 Editor::select_all_selectables_between (bool /*within*/)
1261 list<Selectable *> touched;
1263 if (!get_edit_op_range (start, end)) {
1269 if (selection->tracks.empty()) {
1272 ts = &selection->tracks;
1275 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1276 if ((*iter)->hidden()) {
1279 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1282 selection->set (touched);
1286 Editor::select_range_between ()
1291 if (!get_edit_op_range (start, end)) {
1295 set_mouse_mode (MouseRange);
1296 selection->set ((TimeAxisView*) 0, start, end);
1300 Editor::get_edit_op_range (nframes64_t& start, nframes64_t& end) const
1305 /* in range mode, use any existing selection */
1307 if (mouse_mode == MouseRange && !selection->time.empty()) {
1308 /* we know that these are ordered */
1309 start = selection->time.start();
1310 end = selection->time.end_frame();
1314 if (!mouse_frame (m, ignored)) {
1315 /* mouse is not in a canvas, try playhead+selected marker.
1316 this is probably most true when using menus.
1319 if (selection->markers.empty()) {
1323 start = selection->markers.front()->position();
1324 end = session->audible_frame();
1328 switch (_edit_point) {
1329 case EditAtPlayhead:
1330 if (selection->markers.empty()) {
1331 /* use mouse + playhead */
1333 end = session->audible_frame();
1335 /* use playhead + selected marker */
1336 start = session->audible_frame();
1337 end = selection->markers.front()->position();
1342 /* use mouse + selected marker */
1343 if (selection->markers.empty()) {
1345 end = session->audible_frame();
1347 start = selection->markers.front()->position();
1352 case EditAtSelectedMarker:
1353 /* use mouse + selected marker */
1354 if (selection->markers.empty()) {
1356 MessageDialog win (_("No edit range defined"),
1361 win.set_secondary_text (
1362 _("the edit point is Selected Marker\nbut there is no selected marker."));
1365 win.set_default_response (RESPONSE_CLOSE);
1366 win.set_position (Gtk::WIN_POS_MOUSE);
1371 return false; // NO RANGE
1373 start = selection->markers.front()->position();
1387 /* turn range into one delimited by start...end,
1397 Editor::deselect_all ()
1399 selection->clear ();