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 (Selection::Operation op, bool force)
179 cerr << "E::sstase ca = " << clicked_axisview << " cr = " << clicked_routeview
180 << " op = " << op << " force = " << force
183 if (!clicked_axisview) {
188 if (!clicked_routeview) {
192 RouteGroup* group = clicked_routeview->route()->route_group();
195 case Selection::Toggle:
196 if (selection->selected (clicked_axisview)) {
197 if (_session->all_route_group().is_active()) {
198 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
199 selection->remove(*i);
201 } else if (group && group->is_active()) {
202 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
203 if ((*i)->route_group() == group)
204 selection->remove(*i);
207 selection->remove (clicked_axisview);
210 if (_session->all_route_group().is_active()) {
211 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
214 } else if (group && group->is_active()) {
215 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
216 if ( (*i)->route_group() == group)
220 selection->add (clicked_axisview);
227 cerr << ("Editor::set_selected_track_as_side_effect case Selection::Add not yet implemented\n");
232 if (_session->all_route_group().is_active()) {
233 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
236 } else if (group && group->is_active()) {
237 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
238 if ((*i)->route_group() == group)
242 selection->set (clicked_axisview);
246 case Selection::Extend:
248 cerr << ("Editor::set_selected_track_as_side_effect case Selection::Add not yet implemented\n");
252 #else // the older version
254 if (!selection->tracks.empty()) {
255 if (!selection->selected (clicked_axisview)) {
256 selection->add (clicked_axisview);
260 selection->set (clicked_axisview);
266 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
269 case Selection::Toggle:
270 if (selection->selected (&view)) {
272 selection->remove (&view);
275 selection->add (&view);
280 if (!selection->selected (&view)) {
281 selection->add (&view);
286 selection->set (&view);
289 case Selection::Extend:
290 extend_selection_to_track (view);
296 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
298 if (!clicked_routeview) {
306 set_selected_track (*clicked_routeview, op, no_remove);
310 Editor::set_selected_control_point_from_click (Selection::Operation op, bool /*no_remove*/)
312 if (!clicked_control_point) {
318 selection->set (clicked_control_point);
321 selection->add (clicked_control_point);
323 case Selection::Toggle:
324 selection->toggle (clicked_control_point);
326 case Selection::Extend:
335 Editor::get_onscreen_tracks (TrackViewList& tvl)
337 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
338 if ((*i)->y_position() < _canvas_height) {
344 /** Call a slot for a given `basis' track and also for any track that is in the same
345 * active route group with a particular set of properties.
347 * @param sl Slot to call.
348 * @param basis Basis track.
349 * @param prop Properties that active edit groups must share to be included in the map.
353 Editor::mapover_tracks (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
355 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
357 if (route_basis == 0) {
361 set<RouteTimeAxisView*> tracks;
362 tracks.insert (route_basis);
364 RouteGroup* group = route_basis->route()->route_group();
366 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id) ) {
368 /* the basis is a member of an active route group, with the appropriate
369 properties; find other members */
371 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
372 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
373 if (v && v->route()->route_group() == group) {
380 uint32_t const sz = tracks.size ();
382 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
388 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
390 boost::shared_ptr<Playlist> pl;
391 vector<boost::shared_ptr<Region> > results;
393 boost::shared_ptr<Track> tr;
395 if ((tr = tv.track()) == 0) {
400 if (&tv == &basis->get_time_axis_view()) {
401 /* looking in same track as the original */
405 if ((pl = tr->playlist()) != 0) {
406 pl->get_equivalent_regions (basis->region(), results);
409 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
410 if ((marv = tv.view()->find_view (*ir)) != 0) {
411 all_equivs->push_back (marv);
417 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, PBD::PropertyID property) const
419 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_trackview(), property);
421 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
423 equivalent_regions.push_back (basis);
427 Editor::get_equivalent_regions (RegionSelection & basis, PBD::PropertyID prop) const
429 RegionSelection equivalent;
431 for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
433 vector<RegionView*> eq;
436 sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
437 &(*i)->get_trackview(), prop
440 for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
452 Editor::get_regionview_count_from_region_list (boost::shared_ptr<Region> region)
454 int region_count = 0;
456 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
458 RouteTimeAxisView* tatv;
460 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
462 boost::shared_ptr<Playlist> pl;
463 vector<boost::shared_ptr<Region> > results;
465 boost::shared_ptr<Track> tr;
467 if ((tr = tatv->track()) == 0) {
472 if ((pl = (tr->playlist())) != 0) {
473 pl->get_region_list_equivalent_regions (region, results);
476 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
477 if ((marv = tatv->view()->find_view (*ir)) != 0) {
490 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool /*no_track_remove*/)
492 vector<RegionView*> all_equivalent_regions;
495 if (!clicked_regionview || !clicked_routeview) {
500 button_release_can_deselect = false;
503 if (op == Selection::Toggle || op == Selection::Set) {
507 case Selection::Toggle:
509 if (selection->selected (clicked_regionview)) {
512 /* whatever was clicked was selected already; do nothing here but allow
513 the button release to deselect it
516 button_release_can_deselect = true;
520 if (button_release_can_deselect) {
522 /* just remove this one region, but only on a permitted button release */
524 selection->remove (clicked_regionview);
527 /* no more deselect action on button release till a new press
528 finds an already selected object.
531 button_release_can_deselect = false;
539 if (selection->selected (clicked_routeview)) {
540 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
542 all_equivalent_regions.push_back (clicked_regionview);
545 /* add all the equivalent regions, but only on button press */
547 if (!all_equivalent_regions.empty()) {
551 selection->add (all_equivalent_regions);
557 if (!selection->selected (clicked_regionview)) {
558 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
559 selection->set (all_equivalent_regions);
562 /* no commit necessary: clicked on an already selected region */
572 } else if (op == Selection::Extend) {
574 list<Selectable*> results;
575 nframes64_t last_frame;
576 nframes64_t first_frame;
577 bool same_track = false;
579 /* 1. find the last selected regionview in the track that was clicked in */
582 first_frame = max_frames;
584 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
585 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
587 if ((*x)->region()->last_frame() > last_frame) {
588 last_frame = (*x)->region()->last_frame();
591 if ((*x)->region()->first_frame() < first_frame) {
592 first_frame = (*x)->region()->first_frame();
601 /* 2. figure out the boundaries for our search for new objects */
603 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
605 if (last_frame < clicked_regionview->region()->first_frame()) {
606 first_frame = last_frame;
607 last_frame = clicked_regionview->region()->last_frame();
609 last_frame = first_frame;
610 first_frame = clicked_regionview->region()->first_frame();
614 case OverlapExternal:
615 if (last_frame < clicked_regionview->region()->first_frame()) {
616 first_frame = last_frame;
617 last_frame = clicked_regionview->region()->last_frame();
619 last_frame = first_frame;
620 first_frame = clicked_regionview->region()->first_frame();
624 case OverlapInternal:
625 if (last_frame < clicked_regionview->region()->first_frame()) {
626 first_frame = last_frame;
627 last_frame = clicked_regionview->region()->last_frame();
629 last_frame = first_frame;
630 first_frame = clicked_regionview->region()->first_frame();
636 /* nothing to do except add clicked region to selection, since it
637 overlaps with the existing selection in this track.
644 /* click in a track that has no regions selected, so extend vertically
645 to pick out all regions that are defined by the existing selection
650 first_frame = entered_regionview->region()->position();
651 last_frame = entered_regionview->region()->last_frame();
653 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
654 if ((*i)->region()->position() < first_frame) {
655 first_frame = (*i)->region()->position();
657 if ((*i)->region()->last_frame() + 1 > last_frame) {
658 last_frame = (*i)->region()->last_frame();
663 /* 2. find all the tracks we should select in */
665 set<RouteTimeAxisView*> relevant_tracks;
667 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
668 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
670 relevant_tracks.insert (r);
674 set<RouteTimeAxisView*> already_in_selection;
676 if (relevant_tracks.empty()) {
678 /* no tracks selected .. thus .. if the
679 regionview we're in isn't selected
680 (i.e. we're about to extend to it), then
681 find all tracks between the this one and
685 if (!selection->selected (entered_regionview)) {
687 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&entered_regionview->get_time_axis_view());
691 /* add this track to the ones we will search */
693 relevant_tracks.insert (rtv);
695 /* find the track closest to this one that
696 already a selected region.
699 RouteTimeAxisView* closest = 0;
700 int distance = INT_MAX;
701 int key = rtv->route()->order_key ("editor");
703 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
705 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
707 if (artv && artv != rtv) {
709 pair<set<RouteTimeAxisView*>::iterator,bool> result;
711 result = already_in_selection.insert (artv);
714 /* newly added to already_in_selection */
716 int d = artv->route()->order_key ("editor");
720 if (abs (d) < distance) {
730 /* now add all tracks between that one and this one */
732 int okey = closest->route()->order_key ("editor");
738 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
739 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
740 if (artv && artv != rtv) {
742 int k = artv->route()->order_key ("editor");
744 if (k >= okey && k <= key) {
746 /* in range but don't add it if
747 it already has tracks selected.
748 this avoids odd selection
749 behaviour that feels wrong.
752 if (find (already_in_selection.begin(),
753 already_in_selection.end(),
754 artv) == already_in_selection.end()) {
756 relevant_tracks.insert (artv);
766 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
767 one that was clicked.
770 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
771 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
774 /* 4. convert to a vector of regions */
776 vector<RegionView*> regions;
778 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
781 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
782 regions.push_back (arv);
786 if (!regions.empty()) {
787 selection->add (regions);
798 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
800 vector<RegionView*> all_equivalent_regions;
802 get_regions_corresponding_to (region, all_equivalent_regions);
804 if (all_equivalent_regions.empty()) {
808 begin_reversible_command (_("set selected regions"));
811 case Selection::Toggle:
812 /* XXX this is not correct */
813 selection->toggle (all_equivalent_regions);
816 selection->set (all_equivalent_regions);
818 case Selection::Extend:
819 selection->add (all_equivalent_regions);
822 selection->add (all_equivalent_regions);
826 commit_reversible_command () ;
830 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
833 boost::shared_ptr<Region> r (weak_r.lock());
839 if ((rv = sv->find_view (r)) == 0) {
843 /* don't reset the selection if its something other than
844 a single other region.
847 if (selection->regions.size() > 1) {
851 begin_reversible_command (_("set selected regions"));
855 commit_reversible_command () ;
861 Editor::track_selection_changed ()
863 switch (selection->tracks.size()) {
867 set_selected_mixer_strip (*(selection->tracks.front()));
871 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
873 bool yn = (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end());
875 (*i)->set_selected (yn);
877 TimeAxisView::Children c = (*i)->get_child_list ();
878 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
879 (*j)->set_selected (find (selection->tracks.begin(), selection->tracks.end(), j->get()) != selection->tracks.end());
883 (*i)->reshow_selection (selection->time);
885 (*i)->hide_selection ();
889 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
893 Editor::time_selection_changed ()
895 if (Profile->get_sae()) {
899 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
900 (*i)->hide_selection ();
903 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
904 (*i)->show_selection (selection->time);
907 if (selection->time.empty()) {
908 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
910 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
915 Editor::sensitize_the_right_region_actions (bool have_selected_regions)
917 for (vector<Glib::RefPtr<Action> >::iterator x = ActionManager::region_selection_sensitive_actions.begin();
918 x != ActionManager::region_selection_sensitive_actions.end(); ++x) {
920 string accel_path = (*x)->get_accel_path ();
923 /* if there is an accelerator, it should always be sensitive
924 to allow for keyboard ops on entered regions.
927 bool known = ActionManager::lookup_entry (accel_path, key);
929 if (known && ((key.get_key() != GDK_VoidSymbol) && (key.get_key() != 0))) {
930 (*x)->set_sensitive (true);
932 (*x)->set_sensitive (have_selected_regions);
939 Editor::region_selection_changed ()
941 _regions->block_change_connection (true);
942 editor_regions_selection_changed_connection.block(true);
944 _regions->unselect_all ();
946 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
947 (*i)->set_selected_regionviews (selection->regions);
950 _regions->set_selected (selection->regions);
952 sensitize_the_right_region_actions (!selection->regions.empty());
954 _regions->block_change_connection (false);
955 editor_regions_selection_changed_connection.block(false);
959 Editor::point_selection_changed ()
961 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
962 (*i)->set_selected_points (selection->points);
967 Editor::select_all_in_track (Selection::Operation op)
969 list<Selectable *> touched;
971 if (!clicked_routeview) {
975 clicked_routeview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
978 case Selection::Toggle:
979 selection->add (touched);
982 selection->set (touched);
984 case Selection::Extend:
985 /* meaningless, because we're selecting everything */
988 selection->add (touched);
994 Editor::select_all (Selection::Operation op)
996 list<Selectable *> touched;
998 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
999 if ((*iter)->hidden()) {
1002 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1004 begin_reversible_command (_("select all"));
1006 case Selection::Add:
1007 selection->add (touched);
1009 case Selection::Toggle:
1010 selection->add (touched);
1012 case Selection::Set:
1013 selection->set (touched);
1015 case Selection::Extend:
1016 /* meaningless, because we're selecting everything */
1019 commit_reversible_command ();
1022 Editor::invert_selection_in_track ()
1024 list<Selectable *> touched;
1026 if (!clicked_routeview) {
1030 clicked_routeview->get_inverted_selectables (*selection, touched);
1031 selection->set (touched);
1035 Editor::invert_selection ()
1037 list<Selectable *> touched;
1039 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1040 if ((*iter)->hidden()) {
1043 (*iter)->get_inverted_selectables (*selection, touched);
1046 selection->set (touched);
1049 /** @param start Start time in session frames.
1050 * @param end End time in session frames.
1051 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
1052 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
1053 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
1054 * within the region are already selected.
1057 Editor::select_all_within (
1058 framepos_t start, framepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected
1061 list<Selectable*> found;
1063 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1065 if ((*iter)->hidden()) {
1069 (*iter)->get_selectables (start, end, top, bot, found);
1072 if (found.empty()) {
1076 if (preserve_if_selected && op != Selection::Toggle) {
1077 list<Selectable*>::iterator i = found.begin();
1078 while (i != found.end() && (*i)->get_selected()) {
1082 if (i == found.end()) {
1087 begin_reversible_command (_("select all within"));
1089 case Selection::Add:
1090 selection->add (found);
1092 case Selection::Toggle:
1093 selection->toggle (found);
1095 case Selection::Set:
1096 selection->set (found);
1098 case Selection::Extend:
1099 /* not defined yet */
1103 commit_reversible_command ();
1105 return !found.empty();
1109 Editor::set_selection_from_region ()
1111 if (selection->regions.empty()) {
1115 selection->set (selection->regions.start(), selection->regions.end_frame());
1116 if (!Profile->get_sae()) {
1117 set_mouse_mode (Editing::MouseRange, false);
1122 Editor::set_selection_from_punch()
1126 if ((location = _session->locations()->auto_punch_location()) == 0) {
1130 set_selection_from_range (*location);
1134 Editor::set_selection_from_loop()
1138 if ((location = _session->locations()->auto_loop_location()) == 0) {
1141 set_selection_from_range (*location);
1145 Editor::set_selection_from_range (Location& loc)
1147 begin_reversible_command (_("set selection from range"));
1148 selection->set (loc.start(), loc.end());
1149 commit_reversible_command ();
1151 if (!Profile->get_sae()) {
1152 set_mouse_mode (Editing::MouseRange, false);
1157 Editor::select_all_selectables_using_time_selection ()
1159 list<Selectable *> touched;
1161 if (selection->time.empty()) {
1165 nframes64_t start = selection->time[clicked_selection].start;
1166 nframes64_t end = selection->time[clicked_selection].end;
1168 if (end - 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 (start, end - 1, 0, DBL_MAX, touched);
1187 begin_reversible_command (_("select all from range"));
1188 selection->set (touched);
1189 commit_reversible_command ();
1194 Editor::select_all_selectables_using_punch()
1196 Location* location = _session->locations()->auto_punch_location();
1197 list<Selectable *> touched;
1199 if (location == 0 || (location->end() - location->start() <= 1)) {
1206 if (selection->tracks.empty()) {
1209 ts = &selection->tracks;
1212 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1213 if ((*iter)->hidden()) {
1216 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1218 begin_reversible_command (_("select all from punch"));
1219 selection->set (touched);
1220 commit_reversible_command ();
1225 Editor::select_all_selectables_using_loop()
1227 Location* location = _session->locations()->auto_loop_location();
1228 list<Selectable *> touched;
1230 if (location == 0 || (location->end() - location->start() <= 1)) {
1237 if (selection->tracks.empty()) {
1240 ts = &selection->tracks;
1243 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1244 if ((*iter)->hidden()) {
1247 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1249 begin_reversible_command (_("select all from loop"));
1250 selection->set (touched);
1251 commit_reversible_command ();
1256 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1260 list<Selectable *> touched;
1263 begin_reversible_command (_("select all after cursor"));
1264 start = cursor->current_frame ;
1265 end = _session->current_end_frame();
1267 if (cursor->current_frame > 0) {
1268 begin_reversible_command (_("select all before cursor"));
1270 end = cursor->current_frame - 1;
1279 if (selection->tracks.empty()) {
1282 ts = &selection->tracks;
1285 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1286 if ((*iter)->hidden()) {
1289 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1291 selection->set (touched);
1292 commit_reversible_command ();
1296 Editor::select_all_selectables_using_edit (bool after)
1300 list<Selectable *> touched;
1303 begin_reversible_command (_("select all after edit"));
1304 start = get_preferred_edit_position();
1305 end = _session->current_end_frame();
1307 if ((end = get_preferred_edit_position()) > 1) {
1308 begin_reversible_command (_("select all before edit"));
1319 if (selection->tracks.empty()) {
1322 ts = &selection->tracks;
1325 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1326 if ((*iter)->hidden()) {
1329 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1331 selection->set (touched);
1332 commit_reversible_command ();
1336 Editor::select_all_selectables_between (bool /*within*/)
1340 list<Selectable *> touched;
1342 if (!get_edit_op_range (start, end)) {
1348 if (selection->tracks.empty()) {
1351 ts = &selection->tracks;
1354 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1355 if ((*iter)->hidden()) {
1358 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1361 selection->set (touched);
1365 Editor::select_range_between ()
1370 if (mouse_mode == MouseRange && !selection->time.empty()) {
1371 selection->clear_time ();
1374 if (!get_edit_op_range (start, end)) {
1378 set_mouse_mode (MouseRange);
1379 selection->set (start, end);
1383 Editor::get_edit_op_range (nframes64_t& start, nframes64_t& end) const
1388 /* in range mode, use any existing selection */
1390 if (mouse_mode == MouseRange && !selection->time.empty()) {
1391 /* we know that these are ordered */
1392 start = selection->time.start();
1393 end = selection->time.end_frame();
1397 if (!mouse_frame (m, ignored)) {
1398 /* mouse is not in a canvas, try playhead+selected marker.
1399 this is probably most true when using menus.
1402 if (selection->markers.empty()) {
1406 start = selection->markers.front()->position();
1407 end = _session->audible_frame();
1411 switch (_edit_point) {
1412 case EditAtPlayhead:
1413 if (selection->markers.empty()) {
1414 /* use mouse + playhead */
1416 end = _session->audible_frame();
1418 /* use playhead + selected marker */
1419 start = _session->audible_frame();
1420 end = selection->markers.front()->position();
1425 /* use mouse + selected marker */
1426 if (selection->markers.empty()) {
1428 end = _session->audible_frame();
1430 start = selection->markers.front()->position();
1435 case EditAtSelectedMarker:
1436 /* use mouse + selected marker */
1437 if (selection->markers.empty()) {
1439 MessageDialog win (_("No edit range defined"),
1444 win.set_secondary_text (
1445 _("the edit point is Selected Marker\nbut there is no selected marker."));
1448 win.set_default_response (RESPONSE_CLOSE);
1449 win.set_position (Gtk::WIN_POS_MOUSE);
1454 return false; // NO RANGE
1456 start = selection->markers.front()->position();
1470 /* turn range into one delimited by start...end,
1480 Editor::deselect_all ()
1482 selection->clear ();
1486 Editor::select_range_around_region (RegionView* rv)
1490 selection->set (&rv->get_time_axis_view());
1492 selection->time.clear ();
1493 boost::shared_ptr<Region> r = rv->region ();
1494 return selection->set (r->position(), r->position() + r->length());