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);
174 /** Select clicked_routeview, unless there are no currently selected
175 * tracks, in which case nothing will happen unless `force' is true.
178 Editor::set_selected_track_as_side_effect (bool force)
180 if (!clicked_routeview) {
184 if (!selection->tracks.empty()) {
185 if (!selection->selected (clicked_routeview)) {
186 selection->add (clicked_routeview);
190 selection->set (clicked_routeview);
195 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
198 case Selection::Toggle:
199 if (selection->selected (&view)) {
201 selection->remove (&view);
204 selection->add (&view);
209 if (!selection->selected (&view)) {
210 selection->add (&view);
215 selection->set (&view);
218 case Selection::Extend:
219 extend_selection_to_track (view);
225 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
227 if (!clicked_routeview) {
235 set_selected_track (*clicked_routeview, op, no_remove);
239 Editor::set_selected_control_point_from_click (Selection::Operation op, bool /*no_remove*/)
241 if (!clicked_control_point) {
245 if (clicked_control_point->selected()) {
246 /* the clicked control point is already selected; others may be as well, so
247 don't change the selection.
252 /* We know the ControlPoint that was clicked, but (as discussed in automation_selectable.h)
253 * selected automation data are described by areas on the AutomationLine. A ControlPoint
254 * represents any model points in the space that it takes up, so the AutomationSelectable
255 * needs to be the size of the ControlPoint.
258 double const size = clicked_control_point->size ();
260 nframes64_t const x1 = pixel_to_frame (clicked_control_point->get_x() - size / 2);
261 nframes64_t const x2 = pixel_to_frame (clicked_control_point->get_x() + size / 2);
262 double y1 = clicked_control_point->get_y() - size / 2;
263 double y2 = clicked_control_point->get_y() + size / 2;
265 /* convert the y values to trackview space */
267 clicked_control_point->line().parent_group().i2w (dummy, y1);
268 clicked_control_point->line().parent_group().i2w (dummy, y2);
269 _trackview_group->w2i (dummy, y1);
270 _trackview_group->w2i (dummy, y2);
272 /* and set up the selection */
273 return select_all_within (x1, x2, y1, y2, selection->tracks, Selection::Set);
277 Editor::get_onscreen_tracks (TrackViewList& tvl)
279 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
280 if ((*i)->y_position() < _canvas_height) {
286 /** Call a slot for a given `basis' track and also for any track that is in the same
287 * active route group with a particular set of properties.
289 * @param sl Slot to call.
290 * @param basis Basis track.
291 * @param prop Properties that active edit groups must share to be included in the map.
295 Editor::mapover_tracks (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, RouteGroup::Property prop) const
297 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
298 if (route_basis == 0) {
302 set<RouteTimeAxisView*> tracks;
303 tracks.insert (route_basis);
305 RouteGroup* group = route_basis->route()->route_group();
306 if (group && group->active_property (prop)) {
308 /* the basis is a member of an active route group, with the appropriate
309 properties; find other members */
311 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
312 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
313 if (v && v->route()->route_group() == group) {
320 uint32_t const sz = tracks.size ();
321 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
327 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
329 boost::shared_ptr<Playlist> pl;
330 vector<boost::shared_ptr<Region> > results;
332 boost::shared_ptr<Diskstream> ds;
334 if ((ds = tv.get_diskstream()) == 0) {
339 if (&tv == &basis->get_time_axis_view()) {
340 /* looking in same track as the original */
344 if ((pl = ds->playlist()) != 0) {
345 pl->get_equivalent_regions (basis->region(), results);
348 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
349 if ((marv = tv.view()->find_view (*ir)) != 0) {
350 all_equivs->push_back (marv);
356 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, RouteGroup::Property prop) const
358 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_trackview(), prop);
360 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
362 equivalent_regions.push_back (basis);
366 Editor::get_equivalent_regions (RegionSelection & basis, RouteGroup::Property prop) const
368 RegionSelection equivalent;
370 for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
372 vector<RegionView*> eq;
375 sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
376 &(*i)->get_trackview(), prop
379 for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
391 Editor::get_regionview_count_from_region_list (boost::shared_ptr<Region> region)
393 int region_count = 0;
395 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
397 RouteTimeAxisView* tatv;
399 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
401 boost::shared_ptr<Playlist> pl;
402 vector<boost::shared_ptr<Region> > results;
404 boost::shared_ptr<Diskstream> ds;
406 if ((ds = tatv->get_diskstream()) == 0) {
411 if ((pl = (ds->playlist())) != 0) {
412 pl->get_region_list_equivalent_regions (region, results);
415 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
416 if ((marv = tatv->view()->find_view (*ir)) != 0) {
429 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool /*no_track_remove*/)
431 vector<RegionView*> all_equivalent_regions;
434 if (!clicked_regionview || !clicked_routeview) {
439 button_release_can_deselect = false;
442 if (op == Selection::Toggle || op == Selection::Set) {
446 case Selection::Toggle:
448 if (selection->selected (clicked_regionview)) {
451 /* whatever was clicked was selected already; do nothing here but allow
452 the button release to deselect it
455 button_release_can_deselect = true;
459 if (button_release_can_deselect) {
461 /* just remove this one region, but only on a permitted button release */
463 selection->remove (clicked_regionview);
466 /* no more deselect action on button release till a new press
467 finds an already selected object.
470 button_release_can_deselect = false;
478 if (selection->selected (clicked_routeview)) {
479 get_equivalent_regions (clicked_regionview, all_equivalent_regions, RouteGroup::Select);
481 all_equivalent_regions.push_back (clicked_regionview);
484 /* add all the equivalent regions, but only on button press */
486 if (!all_equivalent_regions.empty()) {
490 selection->add (all_equivalent_regions);
496 if (!selection->selected (clicked_regionview)) {
497 get_equivalent_regions (clicked_regionview, all_equivalent_regions, RouteGroup::Select);
498 selection->set (all_equivalent_regions);
501 /* no commit necessary: clicked on an already selected region */
511 } else if (op == Selection::Extend) {
513 list<Selectable*> results;
514 nframes64_t last_frame;
515 nframes64_t first_frame;
516 bool same_track = false;
518 /* 1. find the last selected regionview in the track that was clicked in */
521 first_frame = max_frames;
523 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
524 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
526 if ((*x)->region()->last_frame() > last_frame) {
527 last_frame = (*x)->region()->last_frame();
530 if ((*x)->region()->first_frame() < first_frame) {
531 first_frame = (*x)->region()->first_frame();
540 /* 2. figure out the boundaries for our search for new objects */
542 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
544 if (last_frame < clicked_regionview->region()->first_frame()) {
545 first_frame = last_frame;
546 last_frame = clicked_regionview->region()->last_frame();
548 last_frame = first_frame;
549 first_frame = clicked_regionview->region()->first_frame();
553 case OverlapExternal:
554 if (last_frame < clicked_regionview->region()->first_frame()) {
555 first_frame = last_frame;
556 last_frame = clicked_regionview->region()->last_frame();
558 last_frame = first_frame;
559 first_frame = clicked_regionview->region()->first_frame();
563 case OverlapInternal:
564 if (last_frame < clicked_regionview->region()->first_frame()) {
565 first_frame = last_frame;
566 last_frame = clicked_regionview->region()->last_frame();
568 last_frame = first_frame;
569 first_frame = clicked_regionview->region()->first_frame();
575 /* nothing to do except add clicked region to selection, since it
576 overlaps with the existing selection in this track.
583 /* click in a track that has no regions selected, so extend vertically
584 to pick out all regions that are defined by the existing selection
589 first_frame = entered_regionview->region()->position();
590 last_frame = entered_regionview->region()->last_frame();
592 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
593 if ((*i)->region()->position() < first_frame) {
594 first_frame = (*i)->region()->position();
596 if ((*i)->region()->last_frame() + 1 > last_frame) {
597 last_frame = (*i)->region()->last_frame();
602 /* 2. find all the tracks we should select in */
604 set<RouteTimeAxisView*> relevant_tracks;
606 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
607 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
609 relevant_tracks.insert (r);
613 set<RouteTimeAxisView*> already_in_selection;
615 if (relevant_tracks.empty()) {
617 /* no tracks selected .. thus .. if the
618 regionview we're in isn't selected
619 (i.e. we're about to extend to it), then
620 find all tracks between the this one and
624 if (!selection->selected (entered_regionview)) {
626 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&entered_regionview->get_time_axis_view());
630 /* add this track to the ones we will search */
632 relevant_tracks.insert (rtv);
634 /* find the track closest to this one that
635 already a selected region.
638 RouteTimeAxisView* closest = 0;
639 int distance = INT_MAX;
640 int key = rtv->route()->order_key ("editor");
642 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
644 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
646 if (artv && artv != rtv) {
648 pair<set<RouteTimeAxisView*>::iterator,bool> result;
650 result = already_in_selection.insert (artv);
653 /* newly added to already_in_selection */
655 int d = artv->route()->order_key ("editor");
659 if (abs (d) < distance) {
669 /* now add all tracks between that one and this one */
671 int okey = closest->route()->order_key ("editor");
677 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
678 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
679 if (artv && artv != rtv) {
681 int k = artv->route()->order_key ("editor");
683 if (k >= okey && k <= key) {
685 /* in range but don't add it if
686 it already has tracks selected.
687 this avoids odd selection
688 behaviour that feels wrong.
691 if (find (already_in_selection.begin(),
692 already_in_selection.end(),
693 artv) == already_in_selection.end()) {
695 relevant_tracks.insert (artv);
705 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
706 one that was clicked.
709 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
710 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
713 /* 4. convert to a vector of regions */
715 vector<RegionView*> regions;
717 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
720 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
721 regions.push_back (arv);
725 if (!regions.empty()) {
726 selection->add (regions);
737 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
739 vector<RegionView*> all_equivalent_regions;
741 get_regions_corresponding_to (region, all_equivalent_regions);
743 if (all_equivalent_regions.empty()) {
747 begin_reversible_command (_("set selected regions"));
750 case Selection::Toggle:
751 /* XXX this is not correct */
752 selection->toggle (all_equivalent_regions);
755 selection->set (all_equivalent_regions);
757 case Selection::Extend:
758 selection->add (all_equivalent_regions);
761 selection->add (all_equivalent_regions);
765 commit_reversible_command () ;
769 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
772 boost::shared_ptr<Region> r (weak_r.lock());
778 if ((rv = sv->find_view (r)) == 0) {
782 /* don't reset the selection if its something other than
783 a single other region.
786 if (selection->regions.size() > 1) {
790 begin_reversible_command (_("set selected regions"));
794 commit_reversible_command () ;
800 Editor::track_selection_changed ()
802 switch (selection->tracks.size()){
806 set_selected_mixer_strip (*(selection->tracks.front()));
810 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
811 if (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end()) {
812 (*i)->set_selected (true);
814 (*i)->set_selected (false);
818 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
822 Editor::time_selection_changed ()
824 if (Profile->get_sae()) {
828 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
829 (*i)->hide_selection ();
832 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
833 (*i)->show_selection (selection->time);
836 if (selection->time.empty()) {
837 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
839 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
844 Editor::sensitize_the_right_region_actions (bool have_selected_regions)
846 for (vector<Glib::RefPtr<Action> >::iterator x = ActionManager::region_selection_sensitive_actions.begin();
847 x != ActionManager::region_selection_sensitive_actions.end(); ++x) {
849 string accel_path = (*x)->get_accel_path ();
852 /* if there is an accelerator, it should always be sensitive
853 to allow for keyboard ops on entered regions.
856 bool known = ActionManager::lookup_entry (accel_path, key);
858 if (known && ((key.get_key() != GDK_VoidSymbol) && (key.get_key() != 0))) {
859 (*x)->set_sensitive (true);
861 (*x)->set_sensitive (have_selected_regions);
868 Editor::region_selection_changed ()
870 _regions->block_change_connection (true);
871 editor_regions_selection_changed_connection.block(true);
873 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
874 (*i)->set_selected_regionviews (selection->regions);
877 _regions->set_selected (selection->regions);
879 sensitize_the_right_region_actions (!selection->regions.empty());
881 _regions->block_change_connection (false);
882 editor_regions_selection_changed_connection.block(false);
886 Editor::point_selection_changed ()
888 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
889 (*i)->set_selected_points (selection->points);
894 Editor::select_all_in_track (Selection::Operation op)
896 list<Selectable *> touched;
898 if (!clicked_routeview) {
902 clicked_routeview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
905 case Selection::Toggle:
906 selection->add (touched);
909 selection->set (touched);
911 case Selection::Extend:
912 /* meaningless, because we're selecting everything */
915 selection->add (touched);
921 Editor::select_all (Selection::Operation op)
923 list<Selectable *> touched;
925 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
926 if ((*iter)->hidden()) {
929 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
931 begin_reversible_command (_("select all"));
934 selection->add (touched);
936 case Selection::Toggle:
937 selection->add (touched);
940 selection->set (touched);
942 case Selection::Extend:
943 /* meaningless, because we're selecting everything */
946 commit_reversible_command ();
949 Editor::invert_selection_in_track ()
951 list<Selectable *> touched;
953 if (!clicked_routeview) {
957 clicked_routeview->get_inverted_selectables (*selection, touched);
958 selection->set (touched);
962 Editor::invert_selection ()
964 list<Selectable *> touched;
966 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
967 if ((*iter)->hidden()) {
970 (*iter)->get_inverted_selectables (*selection, touched);
973 selection->set (touched);
976 /** @param top Top (lower) y limit in trackview coordinates.
977 * @param bottom Bottom (higher) y limit in trackview coordinates.
980 Editor::select_all_within (
981 nframes64_t start, nframes64_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op
984 list<Selectable*> found;
985 TrackViewList tracks;
987 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
989 if ((*iter)->hidden()) {
993 list<Selectable*>::size_type const n = found.size ();
995 (*iter)->get_selectables (start, end, top, bot, found);
997 if (n != found.size()) {
998 tracks.push_back (*iter);
1002 if (found.empty()) {
1006 if (!tracks.empty()) {
1009 case Selection::Add:
1010 selection->add (tracks);
1012 case Selection::Toggle:
1013 selection->toggle (tracks);
1015 case Selection::Set:
1016 selection->set (tracks);
1018 case Selection::Extend:
1019 /* not defined yet */
1024 begin_reversible_command (_("select all within"));
1026 case Selection::Add:
1027 selection->add (found);
1029 case Selection::Toggle:
1030 selection->toggle (found);
1032 case Selection::Set:
1033 selection->set (found);
1035 case Selection::Extend:
1036 /* not defined yet */
1040 commit_reversible_command ();
1042 return !found.empty();
1046 Editor::set_selection_from_region ()
1048 if (selection->regions.empty()) {
1052 selection->set (selection->regions.start(), selection->regions.end_frame());
1053 if (!Profile->get_sae()) {
1054 set_mouse_mode (Editing::MouseRange, false);
1059 Editor::set_selection_from_punch()
1063 if ((location = _session->locations()->auto_punch_location()) == 0) {
1067 set_selection_from_range (*location);
1071 Editor::set_selection_from_loop()
1075 if ((location = _session->locations()->auto_loop_location()) == 0) {
1078 set_selection_from_range (*location);
1082 Editor::set_selection_from_range (Location& loc)
1084 begin_reversible_command (_("set selection from range"));
1085 selection->set (loc.start(), loc.end());
1086 commit_reversible_command ();
1088 if (!Profile->get_sae()) {
1089 set_mouse_mode (Editing::MouseRange, false);
1094 Editor::select_all_selectables_using_time_selection ()
1096 list<Selectable *> touched;
1098 if (selection->time.empty()) {
1102 nframes64_t start = selection->time[clicked_selection].start;
1103 nframes64_t end = selection->time[clicked_selection].end;
1105 if (end - start < 1) {
1111 if (selection->tracks.empty()) {
1114 ts = &selection->tracks;
1117 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1118 if ((*iter)->hidden()) {
1121 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1124 begin_reversible_command (_("select all from range"));
1125 selection->set (touched);
1126 commit_reversible_command ();
1131 Editor::select_all_selectables_using_punch()
1133 Location* location = _session->locations()->auto_punch_location();
1134 list<Selectable *> touched;
1136 if (location == 0 || (location->end() - location->start() <= 1)) {
1143 if (selection->tracks.empty()) {
1146 ts = &selection->tracks;
1149 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1150 if ((*iter)->hidden()) {
1153 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1155 begin_reversible_command (_("select all from punch"));
1156 selection->set (touched);
1157 commit_reversible_command ();
1162 Editor::select_all_selectables_using_loop()
1164 Location* location = _session->locations()->auto_loop_location();
1165 list<Selectable *> touched;
1167 if (location == 0 || (location->end() - location->start() <= 1)) {
1174 if (selection->tracks.empty()) {
1177 ts = &selection->tracks;
1180 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1181 if ((*iter)->hidden()) {
1184 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1186 begin_reversible_command (_("select all from loop"));
1187 selection->set (touched);
1188 commit_reversible_command ();
1193 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1197 list<Selectable *> touched;
1200 begin_reversible_command (_("select all after cursor"));
1201 start = cursor->current_frame ;
1202 end = _session->current_end_frame();
1204 if (cursor->current_frame > 0) {
1205 begin_reversible_command (_("select all before cursor"));
1207 end = cursor->current_frame - 1;
1216 if (selection->tracks.empty()) {
1219 ts = &selection->tracks;
1222 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1223 if ((*iter)->hidden()) {
1226 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1228 selection->set (touched);
1229 commit_reversible_command ();
1233 Editor::select_all_selectables_using_edit (bool after)
1237 list<Selectable *> touched;
1240 begin_reversible_command (_("select all after edit"));
1241 start = get_preferred_edit_position();
1242 end = _session->current_end_frame();
1244 if ((end = get_preferred_edit_position()) > 1) {
1245 begin_reversible_command (_("select all before edit"));
1256 if (selection->tracks.empty()) {
1259 ts = &selection->tracks;
1262 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1263 if ((*iter)->hidden()) {
1266 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1268 selection->set (touched);
1269 commit_reversible_command ();
1273 Editor::select_all_selectables_between (bool /*within*/)
1277 list<Selectable *> touched;
1279 if (!get_edit_op_range (start, end)) {
1285 if (selection->tracks.empty()) {
1288 ts = &selection->tracks;
1291 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1292 if ((*iter)->hidden()) {
1295 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1298 selection->set (touched);
1302 Editor::select_range_between ()
1307 if (!get_edit_op_range (start, end)) {
1311 set_mouse_mode (MouseRange);
1312 selection->set (start, end);
1316 Editor::get_edit_op_range (nframes64_t& start, nframes64_t& end) const
1321 /* in range mode, use any existing selection */
1323 if (mouse_mode == MouseRange && !selection->time.empty()) {
1324 /* we know that these are ordered */
1325 start = selection->time.start();
1326 end = selection->time.end_frame();
1330 if (!mouse_frame (m, ignored)) {
1331 /* mouse is not in a canvas, try playhead+selected marker.
1332 this is probably most true when using menus.
1335 if (selection->markers.empty()) {
1339 start = selection->markers.front()->position();
1340 end = _session->audible_frame();
1344 switch (_edit_point) {
1345 case EditAtPlayhead:
1346 if (selection->markers.empty()) {
1347 /* use mouse + playhead */
1349 end = _session->audible_frame();
1351 /* use playhead + selected marker */
1352 start = _session->audible_frame();
1353 end = selection->markers.front()->position();
1358 /* use mouse + selected marker */
1359 if (selection->markers.empty()) {
1361 end = _session->audible_frame();
1363 start = selection->markers.front()->position();
1368 case EditAtSelectedMarker:
1369 /* use mouse + selected marker */
1370 if (selection->markers.empty()) {
1372 MessageDialog win (_("No edit range defined"),
1377 win.set_secondary_text (
1378 _("the edit point is Selected Marker\nbut there is no selected marker."));
1381 win.set_default_response (RESPONSE_CLOSE);
1382 win.set_position (Gtk::WIN_POS_MOUSE);
1387 return false; // NO RANGE
1389 start = selection->markers.front()->position();
1403 /* turn range into one delimited by start...end,
1413 Editor::deselect_all ()
1415 selection->clear ();
1419 Editor::select_range_around_region (RegionView* rv)
1423 selection->set (&rv->get_time_axis_view());
1425 selection->time.clear ();
1426 boost::shared_ptr<Region> r = rv->region ();
1427 return selection->set (r->position(), r->position() + r->length());