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/playlist.h"
27 #include "ardour/route_group.h"
28 #include "ardour/profile.h"
32 #include "audio_time_axis.h"
33 #include "audio_region_view.h"
34 #include "audio_streamview.h"
35 #include "automation_line.h"
36 #include "control_point.h"
37 #include "editor_regions.h"
42 using namespace ARDOUR;
46 using namespace Gtkmm2ext;
47 using namespace Editing;
49 struct TrackViewByPositionSorter
51 bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
52 return a->y_position() < b->y_position();
57 Editor::extend_selection_to_track (TimeAxisView& view)
59 if (selection->selected (&view)) {
60 /* already selected, do nothing */
64 if (selection->tracks.empty()) {
66 if (!selection->selected (&view)) {
67 selection->set (&view);
74 /* something is already selected, so figure out which range of things to add */
76 TrackViewList to_be_added;
77 TrackViewList sorted = track_views;
78 TrackViewByPositionSorter cmp;
79 bool passed_clicked = false;
84 if (!selection->selected (&view)) {
85 to_be_added.push_back (&view);
88 /* figure out if we should go forward or backwards */
90 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
93 passed_clicked = true;
96 if (selection->selected (*i)) {
106 passed_clicked = false;
110 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
113 passed_clicked = true;
117 if (passed_clicked) {
118 if ((*i)->hidden()) {
121 if (selection->selected (*i)) {
123 } else if (!(*i)->hidden()) {
124 to_be_added.push_back (*i);
131 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
134 passed_clicked = true;
138 if (passed_clicked) {
140 if ((*r)->hidden()) {
144 if (selection->selected (*r)) {
146 } else if (!(*r)->hidden()) {
147 to_be_added.push_back (*r);
153 if (!to_be_added.empty()) {
154 selection->add (to_be_added);
162 Editor::select_all_tracks ()
164 TrackViewList visible_views;
165 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
166 if ((*i)->marked_for_display()) {
167 visible_views.push_back (*i);
170 selection->set (visible_views);
173 /** Select clicked_axisview, unless there are no currently selected
174 * tracks, in which case nothing will happen unless `force' is true.
177 Editor::set_selected_track_as_side_effect (bool force)
179 if (!clicked_axisview) {
183 if (!selection->tracks.empty()) {
184 if (!selection->selected (clicked_axisview)) {
185 selection->add (clicked_axisview);
189 selection->set (clicked_axisview);
194 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
197 case Selection::Toggle:
198 if (selection->selected (&view)) {
200 selection->remove (&view);
203 selection->add (&view);
208 if (!selection->selected (&view)) {
209 selection->add (&view);
214 selection->set (&view);
217 case Selection::Extend:
218 extend_selection_to_track (view);
224 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
226 if (!clicked_routeview) {
234 set_selected_track (*clicked_routeview, op, no_remove);
238 Editor::set_selected_control_point_from_click (Selection::Operation op, bool /*no_remove*/)
240 if (!clicked_control_point) {
244 /* We know the ControlPoint that was clicked, but (as discussed in automation_selectable.h)
245 * selected automation data are described by areas on the AutomationLine. A ControlPoint
246 * represents any model points in the space that it takes up, so the AutomationSelectable
247 * needs to be the size of the ControlPoint.
250 double const size = clicked_control_point->size ();
251 AutomationLine& line = clicked_control_point->line ();
253 nframes64_t const x1 = pixel_to_frame (clicked_control_point->get_x() - size / 2) + line.time_converter().origin_b ();
254 nframes64_t const x2 = pixel_to_frame (clicked_control_point->get_x() + size / 2) + line.time_converter().origin_b ();
255 double y1 = clicked_control_point->get_y() - size / 2;
256 double y2 = clicked_control_point->get_y() + size / 2;
258 /* convert the y values to trackview space */
260 clicked_control_point->line().parent_group().i2w (dummy, y1);
261 clicked_control_point->line().parent_group().i2w (dummy, y2);
262 _trackview_group->w2i (dummy, y1);
263 _trackview_group->w2i (dummy, y2);
265 /* and set up the selection */
266 return select_all_within (x1, x2, y1, y2, selection->tracks, op, true);
270 Editor::get_onscreen_tracks (TrackViewList& tvl)
272 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
273 if ((*i)->y_position() < _canvas_height) {
279 /** Call a slot for a given `basis' track and also for any track that is in the same
280 * active route group with a particular set of properties.
282 * @param sl Slot to call.
283 * @param basis Basis track.
284 * @param prop Properties that active edit groups must share to be included in the map.
288 Editor::mapover_tracks (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
290 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
292 if (route_basis == 0) {
296 set<RouteTimeAxisView*> tracks;
297 tracks.insert (route_basis);
299 RouteGroup* group = route_basis->route()->route_group();
301 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id) ) {
303 /* the basis is a member of an active route group, with the appropriate
304 properties; find other members */
306 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
307 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
308 if (v && v->route()->route_group() == group) {
315 uint32_t const sz = tracks.size ();
317 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
323 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
325 boost::shared_ptr<Playlist> pl;
326 vector<boost::shared_ptr<Region> > results;
328 boost::shared_ptr<Track> tr;
330 if ((tr = tv.track()) == 0) {
335 if (&tv == &basis->get_time_axis_view()) {
336 /* looking in same track as the original */
340 if ((pl = tr->playlist()) != 0) {
341 pl->get_equivalent_regions (basis->region(), results);
344 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
345 if ((marv = tv.view()->find_view (*ir)) != 0) {
346 all_equivs->push_back (marv);
352 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, PBD::PropertyID property) const
354 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_trackview(), property);
356 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
358 equivalent_regions.push_back (basis);
362 Editor::get_equivalent_regions (RegionSelection & basis, PBD::PropertyID prop) const
364 RegionSelection equivalent;
366 for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
368 vector<RegionView*> eq;
371 sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
372 &(*i)->get_trackview(), prop
375 for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
387 Editor::get_regionview_count_from_region_list (boost::shared_ptr<Region> region)
389 int region_count = 0;
391 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
393 RouteTimeAxisView* tatv;
395 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
397 boost::shared_ptr<Playlist> pl;
398 vector<boost::shared_ptr<Region> > results;
400 boost::shared_ptr<Track> tr;
402 if ((tr = tatv->track()) == 0) {
407 if ((pl = (tr->playlist())) != 0) {
408 pl->get_region_list_equivalent_regions (region, results);
411 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
412 if ((marv = tatv->view()->find_view (*ir)) != 0) {
425 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool /*no_track_remove*/)
427 vector<RegionView*> all_equivalent_regions;
430 if (!clicked_regionview || !clicked_routeview) {
435 button_release_can_deselect = false;
438 if (op == Selection::Toggle || op == Selection::Set) {
442 case Selection::Toggle:
444 if (selection->selected (clicked_regionview)) {
447 /* whatever was clicked was selected already; do nothing here but allow
448 the button release to deselect it
451 button_release_can_deselect = true;
455 if (button_release_can_deselect) {
457 /* just remove this one region, but only on a permitted button release */
459 selection->remove (clicked_regionview);
462 /* no more deselect action on button release till a new press
463 finds an already selected object.
466 button_release_can_deselect = false;
474 if (selection->selected (clicked_routeview)) {
475 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
477 all_equivalent_regions.push_back (clicked_regionview);
480 /* add all the equivalent regions, but only on button press */
482 if (!all_equivalent_regions.empty()) {
486 selection->add (all_equivalent_regions);
492 if (!selection->selected (clicked_regionview)) {
493 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
494 selection->set (all_equivalent_regions);
497 /* no commit necessary: clicked on an already selected region */
507 } else if (op == Selection::Extend) {
509 list<Selectable*> results;
510 nframes64_t last_frame;
511 nframes64_t first_frame;
512 bool same_track = false;
514 /* 1. find the last selected regionview in the track that was clicked in */
517 first_frame = max_frames;
519 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
520 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
522 if ((*x)->region()->last_frame() > last_frame) {
523 last_frame = (*x)->region()->last_frame();
526 if ((*x)->region()->first_frame() < first_frame) {
527 first_frame = (*x)->region()->first_frame();
536 /* 2. figure out the boundaries for our search for new objects */
538 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
540 if (last_frame < clicked_regionview->region()->first_frame()) {
541 first_frame = last_frame;
542 last_frame = clicked_regionview->region()->last_frame();
544 last_frame = first_frame;
545 first_frame = clicked_regionview->region()->first_frame();
549 case OverlapExternal:
550 if (last_frame < clicked_regionview->region()->first_frame()) {
551 first_frame = last_frame;
552 last_frame = clicked_regionview->region()->last_frame();
554 last_frame = first_frame;
555 first_frame = clicked_regionview->region()->first_frame();
559 case OverlapInternal:
560 if (last_frame < clicked_regionview->region()->first_frame()) {
561 first_frame = last_frame;
562 last_frame = clicked_regionview->region()->last_frame();
564 last_frame = first_frame;
565 first_frame = clicked_regionview->region()->first_frame();
571 /* nothing to do except add clicked region to selection, since it
572 overlaps with the existing selection in this track.
579 /* click in a track that has no regions selected, so extend vertically
580 to pick out all regions that are defined by the existing selection
585 first_frame = entered_regionview->region()->position();
586 last_frame = entered_regionview->region()->last_frame();
588 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
589 if ((*i)->region()->position() < first_frame) {
590 first_frame = (*i)->region()->position();
592 if ((*i)->region()->last_frame() + 1 > last_frame) {
593 last_frame = (*i)->region()->last_frame();
598 /* 2. find all the tracks we should select in */
600 set<RouteTimeAxisView*> relevant_tracks;
602 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
603 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
605 relevant_tracks.insert (r);
609 set<RouteTimeAxisView*> already_in_selection;
611 if (relevant_tracks.empty()) {
613 /* no tracks selected .. thus .. if the
614 regionview we're in isn't selected
615 (i.e. we're about to extend to it), then
616 find all tracks between the this one and
620 if (!selection->selected (entered_regionview)) {
622 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&entered_regionview->get_time_axis_view());
626 /* add this track to the ones we will search */
628 relevant_tracks.insert (rtv);
630 /* find the track closest to this one that
631 already a selected region.
634 RouteTimeAxisView* closest = 0;
635 int distance = INT_MAX;
636 int key = rtv->route()->order_key ("editor");
638 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
640 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
642 if (artv && artv != rtv) {
644 pair<set<RouteTimeAxisView*>::iterator,bool> result;
646 result = already_in_selection.insert (artv);
649 /* newly added to already_in_selection */
651 int d = artv->route()->order_key ("editor");
655 if (abs (d) < distance) {
665 /* now add all tracks between that one and this one */
667 int okey = closest->route()->order_key ("editor");
673 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
674 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
675 if (artv && artv != rtv) {
677 int k = artv->route()->order_key ("editor");
679 if (k >= okey && k <= key) {
681 /* in range but don't add it if
682 it already has tracks selected.
683 this avoids odd selection
684 behaviour that feels wrong.
687 if (find (already_in_selection.begin(),
688 already_in_selection.end(),
689 artv) == already_in_selection.end()) {
691 relevant_tracks.insert (artv);
701 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
702 one that was clicked.
705 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
706 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
709 /* 4. convert to a vector of regions */
711 vector<RegionView*> regions;
713 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
716 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
717 regions.push_back (arv);
721 if (!regions.empty()) {
722 selection->add (regions);
733 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
735 vector<RegionView*> all_equivalent_regions;
737 get_regions_corresponding_to (region, all_equivalent_regions);
739 if (all_equivalent_regions.empty()) {
743 begin_reversible_command (_("set selected regions"));
746 case Selection::Toggle:
747 /* XXX this is not correct */
748 selection->toggle (all_equivalent_regions);
751 selection->set (all_equivalent_regions);
753 case Selection::Extend:
754 selection->add (all_equivalent_regions);
757 selection->add (all_equivalent_regions);
761 commit_reversible_command () ;
765 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
768 boost::shared_ptr<Region> r (weak_r.lock());
774 if ((rv = sv->find_view (r)) == 0) {
778 /* don't reset the selection if its something other than
779 a single other region.
782 if (selection->regions.size() > 1) {
786 begin_reversible_command (_("set selected regions"));
790 commit_reversible_command () ;
796 Editor::track_selection_changed ()
798 switch (selection->tracks.size()) {
802 set_selected_mixer_strip (*(selection->tracks.front()));
806 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
807 (*i)->set_selected (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end());
809 TimeAxisView::Children c = (*i)->get_child_list ();
810 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
811 (*j)->set_selected (find (selection->tracks.begin(), selection->tracks.end(), j->get()) != selection->tracks.end());
815 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
819 Editor::time_selection_changed ()
821 if (Profile->get_sae()) {
825 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
826 (*i)->hide_selection ();
829 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
830 (*i)->show_selection (selection->time);
833 if (selection->time.empty()) {
834 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
836 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
841 Editor::sensitize_the_right_region_actions (bool have_selected_regions)
843 for (vector<Glib::RefPtr<Action> >::iterator x = ActionManager::region_selection_sensitive_actions.begin();
844 x != ActionManager::region_selection_sensitive_actions.end(); ++x) {
846 string accel_path = (*x)->get_accel_path ();
849 /* if there is an accelerator, it should always be sensitive
850 to allow for keyboard ops on entered regions.
853 bool known = ActionManager::lookup_entry (accel_path, key);
855 if (known && ((key.get_key() != GDK_VoidSymbol) && (key.get_key() != 0))) {
856 (*x)->set_sensitive (true);
858 (*x)->set_sensitive (have_selected_regions);
865 Editor::region_selection_changed ()
867 _regions->block_change_connection (true);
868 editor_regions_selection_changed_connection.block(true);
870 _regions->unselect_all ();
872 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
873 (*i)->set_selected_regionviews (selection->regions);
876 _regions->set_selected (selection->regions);
878 sensitize_the_right_region_actions (!selection->regions.empty());
880 _regions->block_change_connection (false);
881 editor_regions_selection_changed_connection.block(false);
885 Editor::point_selection_changed ()
887 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
888 (*i)->set_selected_points (selection->points);
893 Editor::select_all_in_track (Selection::Operation op)
895 list<Selectable *> touched;
897 if (!clicked_routeview) {
901 clicked_routeview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
904 case Selection::Toggle:
905 selection->add (touched);
908 selection->set (touched);
910 case Selection::Extend:
911 /* meaningless, because we're selecting everything */
914 selection->add (touched);
920 Editor::select_all (Selection::Operation op)
922 list<Selectable *> touched;
924 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
925 if ((*iter)->hidden()) {
928 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
930 begin_reversible_command (_("select all"));
933 selection->add (touched);
935 case Selection::Toggle:
936 selection->add (touched);
939 selection->set (touched);
941 case Selection::Extend:
942 /* meaningless, because we're selecting everything */
945 commit_reversible_command ();
948 Editor::invert_selection_in_track ()
950 list<Selectable *> touched;
952 if (!clicked_routeview) {
956 clicked_routeview->get_inverted_selectables (*selection, touched);
957 selection->set (touched);
961 Editor::invert_selection ()
963 list<Selectable *> touched;
965 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
966 if ((*iter)->hidden()) {
969 (*iter)->get_inverted_selectables (*selection, touched);
972 selection->set (touched);
975 /** @param start Start time in session frames.
976 * @param end End time in session frames.
977 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
978 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
979 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
980 * within the region are already selected.
983 Editor::select_all_within (
984 framepos_t start, framepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected
987 list<Selectable*> found;
989 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
991 if ((*iter)->hidden()) {
995 (*iter)->get_selectables (start, end, top, bot, found);
1002 if (preserve_if_selected && op != Selection::Toggle) {
1003 list<Selectable*>::iterator i = found.begin();
1004 while (i != found.end() && (*i)->get_selected()) {
1008 if (i == found.end()) {
1013 begin_reversible_command (_("select all within"));
1015 case Selection::Add:
1016 selection->add (found);
1018 case Selection::Toggle:
1019 selection->toggle (found);
1021 case Selection::Set:
1022 selection->set (found);
1024 case Selection::Extend:
1025 /* not defined yet */
1029 commit_reversible_command ();
1031 return !found.empty();
1035 Editor::set_selection_from_region ()
1037 if (selection->regions.empty()) {
1041 selection->set (selection->regions.start(), selection->regions.end_frame());
1042 if (!Profile->get_sae()) {
1043 set_mouse_mode (Editing::MouseRange, false);
1048 Editor::set_selection_from_punch()
1052 if ((location = _session->locations()->auto_punch_location()) == 0) {
1056 set_selection_from_range (*location);
1060 Editor::set_selection_from_loop()
1064 if ((location = _session->locations()->auto_loop_location()) == 0) {
1067 set_selection_from_range (*location);
1071 Editor::set_selection_from_range (Location& loc)
1073 begin_reversible_command (_("set selection from range"));
1074 selection->set (loc.start(), loc.end());
1075 commit_reversible_command ();
1077 if (!Profile->get_sae()) {
1078 set_mouse_mode (Editing::MouseRange, false);
1083 Editor::select_all_selectables_using_time_selection ()
1085 list<Selectable *> touched;
1087 if (selection->time.empty()) {
1091 nframes64_t start = selection->time[clicked_selection].start;
1092 nframes64_t end = selection->time[clicked_selection].end;
1094 if (end - start < 1) {
1100 if (selection->tracks.empty()) {
1103 ts = &selection->tracks;
1106 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1107 if ((*iter)->hidden()) {
1110 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1113 begin_reversible_command (_("select all from range"));
1114 selection->set (touched);
1115 commit_reversible_command ();
1120 Editor::select_all_selectables_using_punch()
1122 Location* location = _session->locations()->auto_punch_location();
1123 list<Selectable *> touched;
1125 if (location == 0 || (location->end() - location->start() <= 1)) {
1132 if (selection->tracks.empty()) {
1135 ts = &selection->tracks;
1138 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1139 if ((*iter)->hidden()) {
1142 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1144 begin_reversible_command (_("select all from punch"));
1145 selection->set (touched);
1146 commit_reversible_command ();
1151 Editor::select_all_selectables_using_loop()
1153 Location* location = _session->locations()->auto_loop_location();
1154 list<Selectable *> touched;
1156 if (location == 0 || (location->end() - location->start() <= 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 (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1175 begin_reversible_command (_("select all from loop"));
1176 selection->set (touched);
1177 commit_reversible_command ();
1182 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1186 list<Selectable *> touched;
1189 begin_reversible_command (_("select all after cursor"));
1190 start = cursor->current_frame ;
1191 end = _session->current_end_frame();
1193 if (cursor->current_frame > 0) {
1194 begin_reversible_command (_("select all before cursor"));
1196 end = cursor->current_frame - 1;
1205 if (selection->tracks.empty()) {
1208 ts = &selection->tracks;
1211 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1212 if ((*iter)->hidden()) {
1215 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1217 selection->set (touched);
1218 commit_reversible_command ();
1222 Editor::select_all_selectables_using_edit (bool after)
1226 list<Selectable *> touched;
1229 begin_reversible_command (_("select all after edit"));
1230 start = get_preferred_edit_position();
1231 end = _session->current_end_frame();
1233 if ((end = get_preferred_edit_position()) > 1) {
1234 begin_reversible_command (_("select all before edit"));
1245 if (selection->tracks.empty()) {
1248 ts = &selection->tracks;
1251 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1252 if ((*iter)->hidden()) {
1255 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1257 selection->set (touched);
1258 commit_reversible_command ();
1262 Editor::select_all_selectables_between (bool /*within*/)
1266 list<Selectable *> touched;
1268 if (!get_edit_op_range (start, end)) {
1274 if (selection->tracks.empty()) {
1277 ts = &selection->tracks;
1280 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1281 if ((*iter)->hidden()) {
1284 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1287 selection->set (touched);
1291 Editor::select_range_between ()
1296 if (!get_edit_op_range (start, end)) {
1300 set_mouse_mode (MouseRange);
1301 selection->set (start, end);
1305 Editor::get_edit_op_range (nframes64_t& start, nframes64_t& end) const
1310 /* in range mode, use any existing selection */
1312 if (mouse_mode == MouseRange && !selection->time.empty()) {
1313 /* we know that these are ordered */
1314 start = selection->time.start();
1315 end = selection->time.end_frame();
1319 if (!mouse_frame (m, ignored)) {
1320 /* mouse is not in a canvas, try playhead+selected marker.
1321 this is probably most true when using menus.
1324 if (selection->markers.empty()) {
1328 start = selection->markers.front()->position();
1329 end = _session->audible_frame();
1333 switch (_edit_point) {
1334 case EditAtPlayhead:
1335 if (selection->markers.empty()) {
1336 /* use mouse + playhead */
1338 end = _session->audible_frame();
1340 /* use playhead + selected marker */
1341 start = _session->audible_frame();
1342 end = selection->markers.front()->position();
1347 /* use mouse + selected marker */
1348 if (selection->markers.empty()) {
1350 end = _session->audible_frame();
1352 start = selection->markers.front()->position();
1357 case EditAtSelectedMarker:
1358 /* use mouse + selected marker */
1359 if (selection->markers.empty()) {
1361 MessageDialog win (_("No edit range defined"),
1366 win.set_secondary_text (
1367 _("the edit point is Selected Marker\nbut there is no selected marker."));
1370 win.set_default_response (RESPONSE_CLOSE);
1371 win.set_position (Gtk::WIN_POS_MOUSE);
1376 return false; // NO RANGE
1378 start = selection->markers.front()->position();
1392 /* turn range into one delimited by start...end,
1402 Editor::deselect_all ()
1404 selection->clear ();
1408 Editor::select_range_around_region (RegionView* rv)
1412 selection->set (&rv->get_time_axis_view());
1414 selection->time.clear ();
1415 boost::shared_ptr<Region> r = rv->region ();
1416 return selection->set (r->position(), r->position() + r->length());