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"
24 #include "pbd/unwind.h"
26 #include "ardour/control_protocol_manager.h"
27 #include "ardour/midi_region.h"
28 #include "ardour/playlist.h"
29 #include "ardour/profile.h"
30 #include "ardour/route_group.h"
31 #include "ardour/selection.h"
32 #include "ardour/session.h"
33 #include "ardour/vca.h"
36 #include "editor_drag.h"
37 #include "editor_routes.h"
39 #include "audio_time_axis.h"
40 #include "audio_region_view.h"
41 #include "audio_streamview.h"
42 #include "automation_line.h"
43 #include "control_point.h"
44 #include "editor_regions.h"
45 #include "editor_cursors.h"
46 #include "midi_region_view.h"
52 using namespace ARDOUR;
56 using namespace Gtkmm2ext;
57 using namespace Editing;
59 struct TrackViewByPositionSorter
61 bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
62 return a->y_position() < b->y_position();
67 Editor::extend_selection_to_track (TimeAxisView& view)
69 if (selection->selected (&view)) {
70 /* already selected, do nothing */
74 if (selection->tracks.empty()) {
76 if (!selection->selected (&view)) {
77 selection->set (&view);
84 /* something is already selected, so figure out which range of things to add */
86 TrackViewList to_be_added;
87 TrackViewList sorted = track_views;
88 TrackViewByPositionSorter cmp;
89 bool passed_clicked = false;
94 /* figure out if we should go forward or backwards */
96 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
99 passed_clicked = true;
102 if (selection->selected (*i)) {
103 if (passed_clicked) {
112 passed_clicked = false;
116 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
119 passed_clicked = true;
123 if (passed_clicked) {
124 if ((*i)->hidden()) {
127 if (selection->selected (*i)) {
129 } else if (!(*i)->hidden()) {
130 to_be_added.push_back (*i);
137 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
140 passed_clicked = true;
144 if (passed_clicked) {
146 if ((*r)->hidden()) {
150 if (selection->selected (*r)) {
152 } else if (!(*r)->hidden()) {
153 to_be_added.push_back (*r);
159 if (!selection->selected (&view)) {
160 to_be_added.push_back (&view);
163 if (!to_be_added.empty()) {
164 selection->add (to_be_added);
172 Editor::select_all_tracks ()
174 TrackViewList visible_views;
175 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
176 if ((*i)->marked_for_display()) {
177 visible_views.push_back (*i);
180 PBD::Unwinder<bool> uw (_track_selection_change_without_scroll, true);
181 selection->set (visible_views);
184 /** Select clicked_axisview, unless there are no currently selected
185 * tracks, in which case nothing will happen unless `force' is true.
188 Editor::set_selected_track_as_side_effect (Selection::Operation op)
190 if (!clicked_axisview) {
194 PBD::Unwinder<bool> uw (_editor_track_selection_change_without_scroll, true);
196 RouteGroup* group = NULL;
197 if (clicked_routeview) {
198 group = clicked_routeview->route()->route_group();
202 case Selection::Toggle:
203 if (selection->selected (clicked_axisview)) {
204 if (group && group->is_active()) {
205 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
206 if ((*i)->route_group() == group) {
207 selection->remove(*i);
211 selection->remove (clicked_axisview);
214 if (group && group->is_active()) {
215 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
216 if ((*i)->route_group() == group) {
221 selection->add (clicked_axisview);
227 if (group && group->is_active()) {
228 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
229 if ((*i)->route_group() == group) {
234 selection->add (clicked_axisview);
240 if (group && group->is_active()) {
241 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
242 if ((*i)->route_group() == group) {
247 selection->set (clicked_axisview);
251 case Selection::Extend:
258 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
260 begin_reversible_selection_op (X_("Set Selected Track"));
263 case Selection::Toggle:
264 if (selection->selected (&view)) {
266 selection->remove (&view);
269 selection->add (&view);
274 selection->add (&view);
278 selection->set (&view);
281 case Selection::Extend:
282 extend_selection_to_track (view);
286 commit_reversible_selection_op ();
290 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
292 if (!clicked_routeview) {
300 set_selected_track (*clicked_routeview, op, no_remove);
304 Editor::set_selected_control_point_from_click (bool press, Selection::Operation op)
306 if (!clicked_control_point) {
314 if (!selection->selected (clicked_control_point)) {
315 selection->set (clicked_control_point);
318 /* clicked on an already selected point */
322 if (selection->points.size() > 1) {
323 selection->set (clicked_control_point);
332 selection->add (clicked_control_point);
336 case Selection::Toggle:
338 /* This is a bit of a hack; if we Primary-Click-Drag a control
339 point (for push drag) we want the point we clicked on to be
340 selected, otherwise we end up confusingly dragging an
341 unselected point. So here we ensure that the point is selected
342 after the press, and if we subsequently get a release (meaning no
343 drag occurred) we set things up so that the toggle has happened.
345 if (press && !selection->selected (clicked_control_point)) {
346 /* This is the button press, and the control point is not selected; make it so,
347 in case this press leads to a drag. Also note that having done this, we don't
348 need to toggle again on release.
350 selection->toggle (clicked_control_point);
351 _control_point_toggled_on_press = true;
353 } else if (!press && !_control_point_toggled_on_press) {
354 /* This is the release, and the point wasn't toggled on the press, so do it now */
355 selection->toggle (clicked_control_point);
359 _control_point_toggled_on_press = false;
362 case Selection::Extend:
371 Editor::get_onscreen_tracks (TrackViewList& tvl)
373 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
374 if ((*i)->y_position() < _visible_canvas_height) {
380 /** Call a slot for a given `basis' track and also for any track that is in the same
381 * active route group with a particular set of properties.
383 * @param sl Slot to call.
384 * @param basis Basis track.
385 * @param prop Properties that active edit groups must share to be included in the map.
389 Editor::mapover_tracks (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
391 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
393 if (route_basis == 0) {
397 set<RouteTimeAxisView*> tracks;
398 tracks.insert (route_basis);
400 RouteGroup* group = route_basis->route()->route_group();
402 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id)) {
404 /* the basis is a member of an active route group, with the appropriate
405 properties; find other members */
407 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
408 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
409 if (v && v->route()->route_group() == group) {
416 uint32_t const sz = tracks.size ();
418 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
423 /** Call a slot for a given `basis' track and also for any track that is in the same
424 * active route group with a particular set of properties.
426 * @param sl Slot to call.
427 * @param basis Basis track.
428 * @param prop Properties that active edit groups must share to be included in the map.
432 Editor::mapover_tracks_with_unique_playlists (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
434 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
435 set<boost::shared_ptr<Playlist> > playlists;
437 if (route_basis == 0) {
441 set<RouteTimeAxisView*> tracks;
442 tracks.insert (route_basis);
444 RouteGroup* group = route_basis->route()->route_group(); // could be null, not a problem
446 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id)) {
448 /* the basis is a member of an active route group, with the appropriate
449 properties; find other members */
451 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
452 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
454 if (v && v->route()->route_group() == group) {
456 boost::shared_ptr<Track> t = v->track();
458 if (playlists.insert (t->playlist()).second) {
459 /* haven't seen this playlist yet */
463 /* not actually a "Track", but a timeaxis view that
464 we should mapover anyway.
473 uint32_t const sz = tracks.size ();
475 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
481 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
483 boost::shared_ptr<Playlist> pl;
484 vector<boost::shared_ptr<Region> > results;
486 boost::shared_ptr<Track> tr;
488 if ((tr = tv.track()) == 0) {
493 if (&tv == &basis->get_time_axis_view()) {
494 /* looking in same track as the original */
498 if ((pl = tr->playlist()) != 0) {
499 pl->get_equivalent_regions (basis->region(), results);
502 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
503 if ((marv = tv.view()->find_view (*ir)) != 0) {
504 all_equivs->push_back (marv);
510 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, PBD::PropertyID property) const
512 mapover_tracks_with_unique_playlists (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_time_axis_view(), property);
514 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
516 equivalent_regions.push_back (basis);
520 Editor::get_equivalent_regions (RegionSelection & basis, PBD::PropertyID prop) const
522 RegionSelection equivalent;
524 for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
526 vector<RegionView*> eq;
528 mapover_tracks_with_unique_playlists (
529 sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
530 &(*i)->get_time_axis_view(), prop);
532 for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
543 Editor::get_regionview_count_from_region_list (boost::shared_ptr<Region> region)
545 int region_count = 0;
547 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
549 RouteTimeAxisView* tatv;
551 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
553 boost::shared_ptr<Playlist> pl;
554 vector<boost::shared_ptr<Region> > results;
556 boost::shared_ptr<Track> tr;
558 if ((tr = tatv->track()) == 0) {
563 if ((pl = (tr->playlist())) != 0) {
564 pl->get_region_list_equivalent_regions (region, results);
567 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
568 if ((marv = tatv->view()->find_view (*ir)) != 0) {
581 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op)
583 vector<RegionView*> all_equivalent_regions;
586 if (!clicked_regionview || !clicked_routeview) {
591 button_release_can_deselect = false;
594 if (op == Selection::Toggle || op == Selection::Set) {
597 case Selection::Toggle:
598 if (selection->selected (clicked_regionview)) {
601 /* whatever was clicked was selected already; do nothing here but allow
602 the button release to deselect it
605 button_release_can_deselect = true;
608 if (button_release_can_deselect) {
610 /* just remove this one region, but only on a permitted button release */
612 selection->remove (clicked_regionview);
615 /* no more deselect action on button release till a new press
616 finds an already selected object.
619 button_release_can_deselect = false;
627 if (selection->selected (clicked_routeview)) {
628 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
630 all_equivalent_regions.push_back (clicked_regionview);
633 /* add all the equivalent regions, but only on button press */
635 if (!all_equivalent_regions.empty()) {
639 selection->add (all_equivalent_regions);
645 if (!selection->selected (clicked_regionview)) {
646 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
647 selection->set (all_equivalent_regions);
650 /* clicked on an already selected region */
654 if (selection->regions.size() > 1) {
655 /* collapse region selection down to just this one region (and its equivalents) */
656 get_equivalent_regions(clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
657 selection->set(all_equivalent_regions);
669 } else if (op == Selection::Extend) {
671 list<Selectable*> results;
672 samplepos_t last_sample;
673 samplepos_t first_sample;
674 bool same_track = false;
676 /* 1. find the last selected regionview in the track that was clicked in */
679 first_sample = max_samplepos;
681 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
682 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
684 if ((*x)->region()->last_sample() > last_sample) {
685 last_sample = (*x)->region()->last_sample();
688 if ((*x)->region()->first_sample() < first_sample) {
689 first_sample = (*x)->region()->first_sample();
698 /* 2. figure out the boundaries for our search for new objects */
700 switch (clicked_regionview->region()->coverage (first_sample, last_sample)) {
701 case Evoral::OverlapNone:
702 if (last_sample < clicked_regionview->region()->first_sample()) {
703 first_sample = last_sample;
704 last_sample = clicked_regionview->region()->last_sample();
706 last_sample = first_sample;
707 first_sample = clicked_regionview->region()->first_sample();
711 case Evoral::OverlapExternal:
712 if (last_sample < clicked_regionview->region()->first_sample()) {
713 first_sample = last_sample;
714 last_sample = clicked_regionview->region()->last_sample();
716 last_sample = first_sample;
717 first_sample = clicked_regionview->region()->first_sample();
721 case Evoral::OverlapInternal:
722 if (last_sample < clicked_regionview->region()->first_sample()) {
723 first_sample = last_sample;
724 last_sample = clicked_regionview->region()->last_sample();
726 last_sample = first_sample;
727 first_sample = clicked_regionview->region()->first_sample();
731 case Evoral::OverlapStart:
732 case Evoral::OverlapEnd:
733 /* nothing to do except add clicked region to selection, since it
734 overlaps with the existing selection in this track.
741 /* click in a track that has no regions selected, so extend vertically
742 to pick out all regions that are defined by the existing selection
747 first_sample = clicked_regionview->region()->position();
748 last_sample = clicked_regionview->region()->last_sample();
750 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
751 if ((*i)->region()->position() < first_sample) {
752 first_sample = (*i)->region()->position();
754 if ((*i)->region()->last_sample() + 1 > last_sample) {
755 last_sample = (*i)->region()->last_sample();
760 /* 2. find all the tracks we should select in */
762 set<RouteTimeAxisView*> relevant_tracks;
764 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
765 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
767 relevant_tracks.insert (r);
771 set<RouteTimeAxisView*> already_in_selection;
773 if (relevant_tracks.empty()) {
775 /* no tracks selected .. thus .. if the
776 regionview we're in isn't selected
777 (i.e. we're about to extend to it), then
778 find all tracks between the this one and
782 if (!selection->selected (clicked_regionview)) {
784 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&clicked_regionview->get_time_axis_view());
788 /* add this track to the ones we will search */
790 relevant_tracks.insert (rtv);
792 /* find the track closest to this one that
793 already a selected region.
796 RouteTimeAxisView* closest = 0;
797 int distance = INT_MAX;
798 int key = rtv->route()->presentation_info().order ();
800 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
802 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
804 if (artv && artv != rtv) {
806 pair<set<RouteTimeAxisView*>::iterator,bool> result;
808 result = already_in_selection.insert (artv);
811 /* newly added to already_in_selection */
813 int d = artv->route()->presentation_info().order ();
817 if (abs (d) < distance) {
827 /* now add all tracks between that one and this one */
829 int okey = closest->route()->presentation_info().order ();
835 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
836 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
837 if (artv && artv != rtv) {
839 int k = artv->route()->presentation_info().order ();
841 if (k >= okey && k <= key) {
843 /* in range but don't add it if
844 it already has tracks selected.
845 this avoids odd selection
846 behaviour that feels wrong.
849 if (find (already_in_selection.begin(),
850 already_in_selection.end(),
851 artv) == already_in_selection.end()) {
853 relevant_tracks.insert (artv);
863 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
864 one that was clicked.
867 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
868 (*t)->get_selectables (first_sample, last_sample, -1.0, -1.0, results);
871 /* 4. convert to a vector of regions */
873 vector<RegionView*> regions;
875 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
878 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
879 regions.push_back (arv);
883 if (!regions.empty()) {
884 selection->add (regions);
886 } else if (selection->regions.empty() && !selection->selected (clicked_regionview)) {
887 /* ensure that at least the clicked regionview is selected. */
888 selection->set (clicked_regionview);
899 Editor::set_selection (std::list<Selectable*> s, Selection::Operation op)
904 begin_reversible_selection_op (X_("set selection"));
906 case Selection::Toggle:
907 selection->toggle (s);
912 case Selection::Extend:
920 commit_reversible_selection_op () ;
924 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
926 vector<RegionView*> all_equivalent_regions;
928 get_regions_corresponding_to (region, all_equivalent_regions, region->whole_file());
930 if (all_equivalent_regions.empty()) {
934 begin_reversible_selection_op (X_("set selected regions"));
937 case Selection::Toggle:
938 /* XXX this is not correct */
939 selection->toggle (all_equivalent_regions);
942 selection->set (all_equivalent_regions);
944 case Selection::Extend:
945 selection->add (all_equivalent_regions);
948 selection->add (all_equivalent_regions);
952 commit_reversible_selection_op () ;
956 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
959 boost::shared_ptr<Region> r (weak_r.lock());
965 if ((rv = sv->find_view (r)) == 0) {
969 /* don't reset the selection if its something other than
970 a single other region.
973 if (selection->regions.size() > 1) {
977 begin_reversible_selection_op (X_("set selected regions"));
981 commit_reversible_selection_op () ;
987 Editor::presentation_info_changed (PropertyChange const & what_changed)
989 uint32_t n_tracks = 0;
990 uint32_t n_busses = 0;
992 uint32_t n_routes = 0;
993 uint32_t n_stripables = 0;
995 /* We cannot ensure ordering of the handlers for
996 * PresentationInfo::Changed, so we have to do everything in order
997 * here, as a single handler.
1000 if (what_changed.contains (Properties::selected)) {
1001 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1002 (*i)->set_selected (false);
1003 (*i)->hide_selection ();
1007 /* STEP 1: set the GUI selection state (in which TimeAxisViews for the
1008 * currently selected stripable/controllable duples are found and added
1011 selection->core_selection_changed (what_changed);
1013 /* STEP 2: update TimeAxisView's knowledge of their selected state
1016 if (what_changed.contains (Properties::selected)) {
1018 StripableNotificationListPtr stripables (new StripableNotificationList);
1020 switch (selection->tracks.size()) {
1024 set_selected_mixer_strip (*(selection->tracks.back()));
1025 if (!_track_selection_change_without_scroll && !_editor_track_selection_change_without_scroll) {
1026 ensure_time_axis_view_is_visible (*(selection->tracks.back()), false);
1031 CoreSelection::StripableAutomationControls sc;
1032 _session->selection().get_stripables (sc);
1034 for (CoreSelection::StripableAutomationControls::const_iterator i = sc.begin(); i != sc.end(); ++i) {
1036 AxisView* av = axis_view_by_stripable ((*i).stripable);
1044 if (boost::dynamic_pointer_cast<Track> ((*i).stripable)) {
1047 } else if (boost::dynamic_pointer_cast<Route> ((*i).stripable)) {
1050 } else if (boost::dynamic_pointer_cast<VCA> ((*i).stripable)) {
1054 TimeAxisView* tav = dynamic_cast<TimeAxisView*> (av);
1058 continue; /* impossible */
1061 if (!(*i).controllable) {
1063 /* "parent" track selected */
1064 tav->set_selected (true);
1065 tav->reshow_selection (selection->time);
1069 /* possibly a child */
1071 TimeAxisView::Children c = tav->get_child_list ();
1073 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
1075 boost::shared_ptr<AutomationControl> control = (*j)->control ();
1077 if (control != (*i).controllable) {
1081 (*j)->set_selected (true);
1082 (*j)->reshow_selection (selection->time);
1086 stripables->push_back ((*i).stripable);
1089 ActionManager::set_sensitive (ActionManager::stripable_selection_sensitive_actions, (n_stripables > 0));
1090 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, (n_tracks > 0));
1091 ActionManager::set_sensitive (ActionManager::bus_selection_sensitive_actions, (n_busses > 0));
1092 ActionManager::set_sensitive (ActionManager::route_selection_sensitive_actions, (n_routes > 0));
1093 ActionManager::set_sensitive (ActionManager::vca_selection_sensitive_actions, (n_vcas > 0));
1095 sensitize_the_right_region_actions (false);
1097 /* STEP 4: notify control protocols */
1099 ControlProtocolManager::instance().stripable_selection_changed (stripables);
1101 if (sfbrowser && _session && !_session->deletion_in_progress()) {
1102 uint32_t audio_track_cnt = 0;
1103 uint32_t midi_track_cnt = 0;
1105 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
1106 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*x);
1109 if (atv->is_audio_track()) {
1114 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(*x);
1117 if (mtv->is_midi_track()) {
1124 sfbrowser->reset (audio_track_cnt, midi_track_cnt);
1128 /* STEP 4: update EditorRoutes treeview */
1132 soh.add (Properties::selected);
1133 soh.add (Properties::order);
1134 soh.add (Properties::hidden);
1136 if (what_changed.contains (soh)) {
1137 _routes->sync_treeview_from_presentation_info (what_changed);
1142 Editor::track_selection_changed ()
1144 /* reset paste count, so the plaste location doesn't get incremented
1145 * if we want to paste in the same place, but different track. */
1148 if ( _session->solo_selection_active() )
1149 play_solo_selection(false);
1153 Editor::time_selection_changed ()
1155 /* XXX this is superficially inefficient. Hide the selection in all
1156 * tracks, then show it in all selected tracks.
1158 * However, if you investigate what this actually does, it isn't
1159 * anywhere nearly as bad as it may appear. Remember: nothing is
1160 * redrawn or even recomputed during these two loops - that only
1161 * happens when we next render ...
1164 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1165 (*i)->hide_selection ();
1168 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1169 (*i)->show_selection (selection->time);
1172 if (selection->time.empty()) {
1173 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
1175 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
1178 /* propagate into backend, but only when there is no drag or we are at
1179 * the end of a drag, otherwise this is too expensive (could case a
1180 * locate per mouse motion event.
1183 if (_session && !_drags->active()) {
1184 if (selection->time.length() != 0) {
1185 _session->set_range_selection (selection->time.start(), selection->time.end_sample());
1187 _session->clear_range_selection ();
1192 /** Set all region actions to have a given sensitivity */
1194 Editor::sensitize_all_region_actions (bool s)
1196 Glib::ListHandle<Glib::RefPtr<Action> > all = _region_actions->get_actions ();
1198 for (Glib::ListHandle<Glib::RefPtr<Action> >::iterator i = all.begin(); i != all.end(); ++i) {
1199 (*i)->set_sensitive (s);
1202 _all_region_actions_sensitized = s;
1205 /** Sensitize region-based actions.
1207 * This method is called from whenever we leave the canvas, either by moving
1208 * the pointer out of it, or by popping up a context menu. See
1209 * Editor::{entered,left}_track_canvas() for details there.
1212 Editor::sensitize_the_right_region_actions (bool because_canvas_crossing)
1214 bool have_selection = false;
1215 bool have_entered = false;
1216 bool have_edit_point = false;
1219 // std::cerr << "STRRA: crossing ? " << because_canvas_crossing << " within ? " << within_track_canvas
1222 if (!selection->regions.empty()) {
1223 have_selection = true;
1224 rs = selection->regions;
1227 if (entered_regionview) {
1228 have_entered = true;
1229 rs.add (entered_regionview);
1232 if (rs.empty() && !selection->tracks.empty()) {
1234 /* no selected regions, but some selected tracks.
1237 if (_edit_point == EditAtMouse) {
1238 if (!within_track_canvas) {
1239 /* pointer is not in canvas, so edit point is meaningless */
1240 have_edit_point = false;
1242 /* inside canvas. we don't know where the edit
1243 point will be when an action is invoked, but
1244 assume it could intersect with a region.
1246 have_edit_point = true;
1249 RegionSelection at_edit_point;
1250 samplepos_t const where = get_preferred_edit_position (Editing::EDIT_IGNORE_NONE, false, !within_track_canvas);
1251 get_regions_at (at_edit_point, where, selection->tracks);
1252 if (!at_edit_point.empty()) {
1253 have_edit_point = true;
1256 rs.insert (rs.end(), at_edit_point.begin(), at_edit_point.end());
1261 //std::cerr << "\tfinal have selection: " << have_selection
1262 // << " have entered " << have_entered
1263 // << " have edit point " << have_edit_point
1264 // << " EP = " << enum_2_string (_edit_point)
1267 typedef std::map<std::string,RegionAction> RegionActionMap;
1269 _ignore_region_action = true;
1271 for (RegionActionMap::iterator x = region_action_map.begin(); x != region_action_map.end(); ++x) {
1272 RegionActionTarget tgt = x->second.target;
1273 bool sensitive = false;
1275 if ((tgt & SelectedRegions) && have_selection) {
1277 } else if ((tgt & EnteredRegions) && have_entered) {
1279 } else if ((tgt & EditPointRegions) && have_edit_point) {
1283 x->second.action->set_sensitive (sensitive);
1286 /* Look through the regions that are selected and make notes about what we have got */
1288 bool have_audio = false;
1289 bool have_multichannel_audio = false;
1290 bool have_midi = false;
1291 bool have_locked = false;
1292 bool have_unlocked = false;
1293 bool have_video_locked = false;
1294 bool have_video_unlocked = false;
1295 bool have_position_lock_style_audio = false;
1296 bool have_position_lock_style_music = false;
1297 bool have_muted = false;
1298 bool have_unmuted = false;
1299 bool have_opaque = false;
1300 bool have_non_opaque = false;
1301 bool have_not_at_natural_position = false;
1302 bool have_envelope_active = false;
1303 bool have_envelope_inactive = false;
1304 bool have_non_unity_scale_amplitude = false;
1305 bool have_compound_regions = false;
1306 bool have_inactive_fade_in = false;
1307 bool have_inactive_fade_out = false;
1308 bool have_active_fade_in = false;
1309 bool have_active_fade_out = false;
1310 bool have_transients = false;
1312 for (list<RegionView*>::const_iterator i = rs.begin(); i != rs.end(); ++i) {
1314 boost::shared_ptr<Region> r = (*i)->region ();
1315 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
1319 if (ar->n_channels() > 1) {
1320 have_multichannel_audio = true;
1324 if (boost::dynamic_pointer_cast<MidiRegion> (r)) {
1328 if (r->is_compound()) {
1329 have_compound_regions = true;
1335 have_unlocked = true;
1338 if (r->video_locked()) {
1339 have_video_locked = true;
1341 have_video_unlocked = true;
1344 if (r->position_lock_style() == MusicTime) {
1345 have_position_lock_style_music = true;
1347 have_position_lock_style_audio = true;
1353 have_unmuted = true;
1359 have_non_opaque = true;
1362 if (!r->at_natural_position()) {
1363 have_not_at_natural_position = true;
1366 if (r->has_transients ()){
1367 have_transients = true;
1371 if (ar->envelope_active()) {
1372 have_envelope_active = true;
1374 have_envelope_inactive = true;
1377 if (ar->scale_amplitude() != 1) {
1378 have_non_unity_scale_amplitude = true;
1381 if (ar->fade_in_active ()) {
1382 have_active_fade_in = true;
1384 have_inactive_fade_in = true;
1387 if (ar->fade_out_active ()) {
1388 have_active_fade_out = true;
1390 have_inactive_fade_out = true;
1395 _region_actions->get_action("split-region-at-transients")->set_sensitive (have_transients);
1397 if (rs.size() > 1) {
1398 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1399 _region_actions->get_action("show-region-properties")->set_sensitive (false);
1400 _region_actions->get_action("rename-region")->set_sensitive (false);
1402 /* XXX need to check whether there is than 1 per
1403 playlist, because otherwise this makes no sense.
1405 _region_actions->get_action("combine-regions")->set_sensitive (true);
1407 _region_actions->get_action("combine-regions")->set_sensitive (false);
1409 } else if (rs.size() == 1) {
1410 _region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
1411 _region_actions->get_action("close-region-gaps")->set_sensitive (false);
1412 _region_actions->get_action("combine-regions")->set_sensitive (false);
1415 if (!have_multichannel_audio) {
1416 _region_actions->get_action("split-multichannel-region")->set_sensitive (false);
1420 editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (false);
1421 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1422 _region_actions->get_action("quantize-region")->set_sensitive (false);
1423 _region_actions->get_action("legatize-region")->set_sensitive (false);
1424 _region_actions->get_action("remove-overlap")->set_sensitive (false);
1425 _region_actions->get_action("transform-region")->set_sensitive (false);
1426 _region_actions->get_action("fork-region")->set_sensitive (false);
1427 _region_actions->get_action("insert-patch-change-context")->set_sensitive (false);
1428 _region_actions->get_action("insert-patch-change")->set_sensitive (false);
1429 _region_actions->get_action("transpose-region")->set_sensitive (false);
1431 editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (true);
1432 /* others were already marked sensitive */
1435 /* ok, moving along... */
1437 if (have_compound_regions) {
1438 _region_actions->get_action("uncombine-regions")->set_sensitive (true);
1440 _region_actions->get_action("uncombine-regions")->set_sensitive (false);
1445 if (have_envelope_active && !have_envelope_inactive) {
1446 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active ();
1447 } else if (have_envelope_active && have_envelope_inactive) {
1448 // Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_inconsistent ();
1453 _region_actions->get_action("loudness-analyze-region")->set_sensitive (false);
1454 _region_actions->get_action("spectral-analyze-region")->set_sensitive (false);
1455 _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
1456 _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
1457 _region_actions->get_action("pitch-shift-region")->set_sensitive (false);
1458 _region_actions->get_action("strip-region-silence")->set_sensitive (false);
1459 _region_actions->get_action("show-rhythm-ferret")->set_sensitive (false);
1463 if (!have_non_unity_scale_amplitude || !have_audio) {
1464 _region_actions->get_action("reset-region-scale-amplitude")->set_sensitive (false);
1467 Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"));
1468 a->set_active (have_locked && !have_unlocked);
1469 if (have_locked && have_unlocked) {
1470 // a->set_inconsistent ();
1473 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-video-lock"));
1474 a->set_active (have_video_locked && !have_video_unlocked);
1475 if (have_video_locked && have_video_unlocked) {
1476 // a->set_inconsistent ();
1479 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
1480 a->set_active (have_position_lock_style_music && !have_position_lock_style_audio);
1482 vector<Widget*> proxies = a->get_proxies();
1483 for (vector<Widget*>::iterator p = proxies.begin(); p != proxies.end(); ++p) {
1484 Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (*p);
1486 cmi->set_inconsistent (have_position_lock_style_music && have_position_lock_style_audio);
1490 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"));
1491 a->set_active (have_muted && !have_unmuted);
1492 if (have_muted && have_unmuted) {
1493 // a->set_inconsistent ();
1496 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"));
1497 a->set_active (have_opaque && !have_non_opaque);
1498 if (have_opaque && have_non_opaque) {
1499 // a->set_inconsistent ();
1502 if (!have_not_at_natural_position) {
1503 _region_actions->get_action("naturalize-region")->set_sensitive (false);
1506 /* XXX: should also check that there is a track of the appropriate type for the selected region */
1507 if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
1508 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (false);
1510 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (true);
1513 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-in"));
1514 a->set_active (have_active_fade_in && !have_inactive_fade_in);
1515 if (have_active_fade_in && have_inactive_fade_in) {
1516 // a->set_inconsistent ();
1519 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-out"));
1520 a->set_active (have_active_fade_out && !have_inactive_fade_out);
1522 if (have_active_fade_out && have_inactive_fade_out) {
1523 // a->set_inconsistent ();
1526 bool const have_active_fade = have_active_fade_in || have_active_fade_out;
1527 bool const have_inactive_fade = have_inactive_fade_in || have_inactive_fade_out;
1529 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fades"));
1530 a->set_active (have_active_fade && !have_inactive_fade);
1532 if (have_active_fade && have_inactive_fade) {
1533 // a->set_inconsistent ();
1536 _ignore_region_action = false;
1538 _all_region_actions_sensitized = false;
1542 Editor::region_selection_changed ()
1544 _regions->block_change_connection (true);
1545 editor_regions_selection_changed_connection.block(true);
1547 if (_region_selection_change_updates_region_list) {
1548 _regions->unselect_all ();
1551 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1552 (*i)->set_selected_regionviews (selection->regions);
1555 if (_region_selection_change_updates_region_list) {
1556 _regions->set_selected (selection->regions);
1559 _regions->block_change_connection (false);
1560 editor_regions_selection_changed_connection.block(false);
1562 sensitize_the_right_region_actions (false);
1564 /* propagate into backend */
1567 if (!selection->regions.empty()) {
1568 _session->set_object_selection (selection->regions.start(), selection->regions.end_sample());
1570 _session->clear_object_selection ();
1574 if (_session->solo_selection_active()) {
1575 play_solo_selection(false);
1578 /* set nudge button color */
1579 if (! get_regions_from_selection_and_entered().empty()) {
1581 nudge_forward_button.set_name ("nudge button");
1582 nudge_backward_button.set_name ("nudge button");
1584 /* nudge marker or playhead */
1585 nudge_forward_button.set_name ("generic button");
1586 nudge_backward_button.set_name ("generic button");
1591 Editor::point_selection_changed ()
1593 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1594 (*i)->set_selected_points (selection->points);
1599 Editor::select_all_in_track (Selection::Operation op)
1601 list<Selectable *> touched;
1603 if (!clicked_routeview) {
1607 begin_reversible_selection_op (X_("Select All in Track"));
1609 clicked_routeview->get_selectables (0, max_samplepos, 0, DBL_MAX, touched);
1612 case Selection::Toggle:
1613 selection->add (touched);
1615 case Selection::Set:
1616 selection->set (touched);
1618 case Selection::Extend:
1619 /* meaningless, because we're selecting everything */
1621 case Selection::Add:
1622 selection->add (touched);
1626 commit_reversible_selection_op ();
1630 Editor::select_all_internal_edit (Selection::Operation)
1632 bool selected = false;
1634 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1635 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1637 mrv->select_all_notes ();
1642 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(entered_regionview);
1644 mrv->select_all_notes ();
1652 Editor::select_all_objects (Selection::Operation op)
1654 list<Selectable *> touched;
1656 if (internal_editing() && select_all_internal_edit(op)) {
1657 return; // Selected notes
1662 if (selection->tracks.empty()) {
1665 ts = selection->tracks;
1668 for (TrackViewList::iterator iter = ts.begin(); iter != ts.end(); ++iter) {
1669 if ((*iter)->hidden()) {
1672 (*iter)->get_selectables (0, max_samplepos, 0, DBL_MAX, touched);
1675 begin_reversible_selection_op (X_("select all"));
1677 case Selection::Add:
1678 selection->add (touched);
1680 case Selection::Toggle:
1681 selection->toggle (touched);
1683 case Selection::Set:
1684 selection->set (touched);
1686 case Selection::Extend:
1687 /* meaningless, because we're selecting everything */
1690 commit_reversible_selection_op ();
1694 Editor::invert_selection_in_track ()
1696 list<Selectable *> touched;
1698 if (!clicked_routeview) {
1702 begin_reversible_selection_op (X_("Invert Selection in Track"));
1703 clicked_routeview->get_inverted_selectables (*selection, touched);
1704 selection->set (touched);
1705 commit_reversible_selection_op ();
1709 Editor::invert_selection ()
1712 if (internal_editing()) {
1713 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1714 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1716 mrv->invert_selection ();
1722 if (!selection->tracks.empty()) {
1724 TrackViewList inverted;
1726 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1727 if (!(*iter)->selected()) {
1728 inverted.push_back (*iter);
1732 begin_reversible_selection_op (X_("Invert Track Selection"));
1733 selection->set (inverted);
1734 commit_reversible_selection_op ();
1738 list<Selectable *> touched;
1740 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1741 if ((*iter)->hidden()) {
1744 (*iter)->get_inverted_selectables (*selection, touched);
1747 begin_reversible_selection_op (X_("Invert ObjectSelection"));
1748 selection->set (touched);
1749 commit_reversible_selection_op ();
1753 /** @param start Start time in session samples.
1754 * @param end End time in session samples.
1755 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
1756 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
1757 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
1758 * within the region are already selected.
1761 Editor::select_all_within (samplepos_t start, samplepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected)
1763 list<Selectable*> found;
1765 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1767 if ((*iter)->hidden()) {
1771 (*iter)->get_selectables (start, end, top, bot, found);
1774 if (found.empty()) {
1775 selection->clear_objects();
1776 selection->clear_time ();
1780 if (preserve_if_selected && op != Selection::Toggle) {
1781 list<Selectable*>::iterator i = found.begin();
1782 while (i != found.end() && (*i)->selected()) {
1786 if (i == found.end()) {
1791 begin_reversible_selection_op (X_("select all within"));
1793 case Selection::Add:
1794 selection->add (found);
1796 case Selection::Toggle:
1797 selection->toggle (found);
1799 case Selection::Set:
1800 selection->set (found);
1802 case Selection::Extend:
1803 /* not defined yet */
1807 commit_reversible_selection_op ();
1811 Editor::set_selection_from_region ()
1813 if (selection->regions.empty()) {
1817 /* find all the tracks that have selected regions */
1819 set<TimeAxisView*> tracks;
1821 for (RegionSelection::const_iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
1822 tracks.insert (&(*r)->get_time_axis_view());
1826 tvl.insert (tvl.end(), tracks.begin(), tracks.end());
1828 /* select range (this will clear the region selection) */
1830 selection->set (selection->regions.start(), selection->regions.end_sample());
1832 /* and select the tracks */
1834 selection->set (tvl);
1836 if (!get_smart_mode () || !(mouse_mode == Editing::MouseObject) ) {
1837 set_mouse_mode (Editing::MouseRange, false);
1842 Editor::set_selection_from_punch()
1846 if ((location = _session->locations()->auto_punch_location()) == 0) {
1850 set_selection_from_range (*location);
1854 Editor::set_selection_from_loop()
1858 if ((location = _session->locations()->auto_loop_location()) == 0) {
1861 set_selection_from_range (*location);
1865 Editor::set_selection_from_range (Location& loc)
1867 begin_reversible_selection_op (X_("set selection from range"));
1869 selection->set (loc.start(), loc.end());
1871 // if no tracks are selected, enable all tracks
1872 // (_something_ has to be selected for any range selection, otherwise the user won't see anything)
1873 if (selection->tracks.empty()) {
1874 select_all_tracks();
1877 commit_reversible_selection_op ();
1879 if (!get_smart_mode () || mouse_mode != Editing::MouseObject) {
1880 set_mouse_mode (MouseRange, false);
1885 Editor::select_all_selectables_using_time_selection ()
1887 list<Selectable *> touched;
1889 if (selection->time.empty()) {
1893 samplepos_t start = selection->time[clicked_selection].start;
1894 samplepos_t end = selection->time[clicked_selection].end;
1896 if (end - start < 1) {
1902 if (selection->tracks.empty()) {
1905 ts = &selection->tracks;
1908 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1909 if ((*iter)->hidden()) {
1912 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1915 begin_reversible_selection_op (X_("select all from range"));
1916 selection->set (touched);
1917 commit_reversible_selection_op ();
1922 Editor::select_all_selectables_using_punch()
1924 Location* location = _session->locations()->auto_punch_location();
1925 list<Selectable *> touched;
1927 if (location == 0 || (location->end() - location->start() <= 1)) {
1934 if (selection->tracks.empty()) {
1937 ts = &selection->tracks;
1940 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1941 if ((*iter)->hidden()) {
1944 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1946 begin_reversible_selection_op (X_("select all from punch"));
1947 selection->set (touched);
1948 commit_reversible_selection_op ();
1953 Editor::select_all_selectables_using_loop()
1955 Location* location = _session->locations()->auto_loop_location();
1956 list<Selectable *> touched;
1958 if (location == 0 || (location->end() - location->start() <= 1)) {
1965 if (selection->tracks.empty()) {
1968 ts = &selection->tracks;
1971 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1972 if ((*iter)->hidden()) {
1975 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1977 begin_reversible_selection_op (X_("select all from loop"));
1978 selection->set (touched);
1979 commit_reversible_selection_op ();
1984 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1988 list<Selectable *> touched;
1991 start = cursor->current_sample();
1992 end = _session->current_end_sample();
1994 if (cursor->current_sample() > 0) {
1996 end = cursor->current_sample() - 1;
2002 if (internal_editing()) {
2003 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2004 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
2006 mrv->select_range (start, end);
2013 begin_reversible_selection_op (X_("select all after cursor"));
2015 begin_reversible_selection_op (X_("select all before cursor"));
2020 if (selection->tracks.empty()) {
2023 ts = &selection->tracks;
2026 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
2027 if ((*iter)->hidden()) {
2030 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
2032 selection->set (touched);
2033 commit_reversible_selection_op ();
2037 Editor::select_all_selectables_using_edit (bool after, bool from_context_menu)
2041 list<Selectable *> touched;
2044 start = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu);
2045 end = _session->current_end_sample();
2047 if ((end = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu)) > 1) {
2055 if (internal_editing()) {
2056 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2057 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
2058 mrv->select_range (start, end);
2064 begin_reversible_selection_op (X_("select all after edit"));
2066 begin_reversible_selection_op (X_("select all before edit"));
2071 if (selection->tracks.empty()) {
2074 ts = &selection->tracks;
2077 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
2078 if ((*iter)->hidden()) {
2081 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
2083 selection->set (touched);
2084 commit_reversible_selection_op ();
2088 Editor::select_all_selectables_between (bool within)
2092 list<Selectable *> touched;
2094 if (!get_edit_op_range (start, end)) {
2098 if (internal_editing()) {
2099 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2100 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
2101 mrv->select_range (start, end);
2108 if (selection->tracks.empty()) {
2111 ts = &selection->tracks;
2114 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
2115 if ((*iter)->hidden()) {
2118 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched, within);
2121 begin_reversible_selection_op (X_("Select all Selectables Between"));
2122 selection->set (touched);
2123 commit_reversible_selection_op ();
2127 Editor::select_range_between ()
2132 if (!selection->time.empty()) {
2133 selection->clear_time ();
2136 if (!get_edit_op_range (start, end)) {
2140 if (!get_smart_mode () || mouse_mode != Editing::MouseObject) {
2141 set_mouse_mode (MouseRange, false);
2144 begin_reversible_selection_op (X_("Select Range Between"));
2145 selection->set (start, end);
2146 commit_reversible_selection_op ();
2150 Editor::get_edit_op_range (samplepos_t& start, samplepos_t& end) const
2155 /* if an explicit range exists, use it */
2157 if ((mouse_mode == MouseRange || get_smart_mode()) && !selection->time.empty()) {
2158 /* we know that these are ordered */
2159 start = selection->time.start();
2160 end = selection->time.end_sample();
2168 // if (!mouse_sample (m, ignored)) {
2169 // /* mouse is not in a canvas, try playhead+selected marker.
2170 // this is probably most true when using menus.
2173 // if (selection->markers.empty()) {
2177 // start = selection->markers.front()->position();
2178 // end = _session->audible_sample();
2182 // switch (_edit_point) {
2183 // case EditAtPlayhead:
2184 // if (selection->markers.empty()) {
2185 // /* use mouse + playhead */
2187 // end = _session->audible_sample();
2189 // /* use playhead + selected marker */
2190 // start = _session->audible_sample();
2191 // end = selection->markers.front()->position();
2195 // case EditAtMouse:
2196 // /* use mouse + selected marker */
2197 // if (selection->markers.empty()) {
2199 // end = _session->audible_sample();
2201 // start = selection->markers.front()->position();
2206 // case EditAtSelectedMarker:
2207 // /* use mouse + selected marker */
2208 // if (selection->markers.empty()) {
2210 // MessageDialog win (_("No edit range defined"),
2215 // win.set_secondary_text (
2216 // _("the edit point is Selected Marker\nbut there is no selected marker."));
2219 // win.set_default_response (RESPONSE_CLOSE);
2220 // win.set_position (Gtk::WIN_POS_MOUSE);
2225 // return false; // NO RANGE
2227 // start = selection->markers.front()->position();
2233 // if (start == end) {
2237 // if (start > end) {
2238 // swap (start, end);
2241 /* turn range into one delimited by start...end,
2251 Editor::deselect_all ()
2253 begin_reversible_selection_op (X_("Deselect All"));
2254 selection->clear ();
2255 commit_reversible_selection_op ();
2259 Editor::select_range (samplepos_t s, samplepos_t e)
2261 begin_reversible_selection_op (X_("Select Range"));
2262 selection->add (clicked_axisview);
2263 selection->time.clear ();
2264 long ret = selection->set (s, e);
2265 commit_reversible_selection_op ();