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 all of the selectables within the region are already selected.
982 Editor::select_all_within (
983 framepos_t start, framepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected
986 list<Selectable*> found;
988 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
990 if ((*iter)->hidden()) {
994 (*iter)->get_selectables (start, end, top, bot, found);
1001 if (preserve_if_selected) {
1002 list<Selectable*>::iterator i = found.begin();
1003 while (i != found.end() && (*i)->get_selected()) {
1007 if (i == found.end()) {
1012 begin_reversible_command (_("select all within"));
1014 case Selection::Add:
1015 selection->add (found);
1017 case Selection::Toggle:
1018 selection->toggle (found);
1020 case Selection::Set:
1021 selection->set (found);
1023 case Selection::Extend:
1024 /* not defined yet */
1028 commit_reversible_command ();
1030 return !found.empty();
1034 Editor::set_selection_from_region ()
1036 if (selection->regions.empty()) {
1040 selection->set (selection->regions.start(), selection->regions.end_frame());
1041 if (!Profile->get_sae()) {
1042 set_mouse_mode (Editing::MouseRange, false);
1047 Editor::set_selection_from_punch()
1051 if ((location = _session->locations()->auto_punch_location()) == 0) {
1055 set_selection_from_range (*location);
1059 Editor::set_selection_from_loop()
1063 if ((location = _session->locations()->auto_loop_location()) == 0) {
1066 set_selection_from_range (*location);
1070 Editor::set_selection_from_range (Location& loc)
1072 begin_reversible_command (_("set selection from range"));
1073 selection->set (loc.start(), loc.end());
1074 commit_reversible_command ();
1076 if (!Profile->get_sae()) {
1077 set_mouse_mode (Editing::MouseRange, false);
1082 Editor::select_all_selectables_using_time_selection ()
1084 list<Selectable *> touched;
1086 if (selection->time.empty()) {
1090 nframes64_t start = selection->time[clicked_selection].start;
1091 nframes64_t end = selection->time[clicked_selection].end;
1093 if (end - start < 1) {
1099 if (selection->tracks.empty()) {
1102 ts = &selection->tracks;
1105 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1106 if ((*iter)->hidden()) {
1109 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1112 begin_reversible_command (_("select all from range"));
1113 selection->set (touched);
1114 commit_reversible_command ();
1119 Editor::select_all_selectables_using_punch()
1121 Location* location = _session->locations()->auto_punch_location();
1122 list<Selectable *> touched;
1124 if (location == 0 || (location->end() - location->start() <= 1)) {
1131 if (selection->tracks.empty()) {
1134 ts = &selection->tracks;
1137 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1138 if ((*iter)->hidden()) {
1141 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1143 begin_reversible_command (_("select all from punch"));
1144 selection->set (touched);
1145 commit_reversible_command ();
1150 Editor::select_all_selectables_using_loop()
1152 Location* location = _session->locations()->auto_loop_location();
1153 list<Selectable *> touched;
1155 if (location == 0 || (location->end() - location->start() <= 1)) {
1162 if (selection->tracks.empty()) {
1165 ts = &selection->tracks;
1168 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1169 if ((*iter)->hidden()) {
1172 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1174 begin_reversible_command (_("select all from loop"));
1175 selection->set (touched);
1176 commit_reversible_command ();
1181 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1185 list<Selectable *> touched;
1188 begin_reversible_command (_("select all after cursor"));
1189 start = cursor->current_frame ;
1190 end = _session->current_end_frame();
1192 if (cursor->current_frame > 0) {
1193 begin_reversible_command (_("select all before cursor"));
1195 end = cursor->current_frame - 1;
1204 if (selection->tracks.empty()) {
1207 ts = &selection->tracks;
1210 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1211 if ((*iter)->hidden()) {
1214 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1216 selection->set (touched);
1217 commit_reversible_command ();
1221 Editor::select_all_selectables_using_edit (bool after)
1225 list<Selectable *> touched;
1228 begin_reversible_command (_("select all after edit"));
1229 start = get_preferred_edit_position();
1230 end = _session->current_end_frame();
1232 if ((end = get_preferred_edit_position()) > 1) {
1233 begin_reversible_command (_("select all before edit"));
1244 if (selection->tracks.empty()) {
1247 ts = &selection->tracks;
1250 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1251 if ((*iter)->hidden()) {
1254 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1256 selection->set (touched);
1257 commit_reversible_command ();
1261 Editor::select_all_selectables_between (bool /*within*/)
1265 list<Selectable *> touched;
1267 if (!get_edit_op_range (start, end)) {
1273 if (selection->tracks.empty()) {
1276 ts = &selection->tracks;
1279 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1280 if ((*iter)->hidden()) {
1283 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1286 selection->set (touched);
1290 Editor::select_range_between ()
1295 if (!get_edit_op_range (start, end)) {
1299 set_mouse_mode (MouseRange);
1300 selection->set (start, end);
1304 Editor::get_edit_op_range (nframes64_t& start, nframes64_t& end) const
1309 /* in range mode, use any existing selection */
1311 if (mouse_mode == MouseRange && !selection->time.empty()) {
1312 /* we know that these are ordered */
1313 start = selection->time.start();
1314 end = selection->time.end_frame();
1318 if (!mouse_frame (m, ignored)) {
1319 /* mouse is not in a canvas, try playhead+selected marker.
1320 this is probably most true when using menus.
1323 if (selection->markers.empty()) {
1327 start = selection->markers.front()->position();
1328 end = _session->audible_frame();
1332 switch (_edit_point) {
1333 case EditAtPlayhead:
1334 if (selection->markers.empty()) {
1335 /* use mouse + playhead */
1337 end = _session->audible_frame();
1339 /* use playhead + selected marker */
1340 start = _session->audible_frame();
1341 end = selection->markers.front()->position();
1346 /* use mouse + selected marker */
1347 if (selection->markers.empty()) {
1349 end = _session->audible_frame();
1351 start = selection->markers.front()->position();
1356 case EditAtSelectedMarker:
1357 /* use mouse + selected marker */
1358 if (selection->markers.empty()) {
1360 MessageDialog win (_("No edit range defined"),
1365 win.set_secondary_text (
1366 _("the edit point is Selected Marker\nbut there is no selected marker."));
1369 win.set_default_response (RESPONSE_CLOSE);
1370 win.set_position (Gtk::WIN_POS_MOUSE);
1375 return false; // NO RANGE
1377 start = selection->markers.front()->position();
1391 /* turn range into one delimited by start...end,
1401 Editor::deselect_all ()
1403 selection->clear ();
1407 Editor::select_range_around_region (RegionView* rv)
1411 selection->set (&rv->get_time_axis_view());
1413 selection->time.clear ();
1414 boost::shared_ptr<Region> r = rv->region ();
1415 return selection->set (r->position(), r->position() + r->length());