2 Copyright (C) 2000-2018 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"
38 #include "editor_sources.h"
40 #include "audio_time_axis.h"
41 #include "audio_region_view.h"
42 #include "audio_streamview.h"
43 #include "automation_line.h"
44 #include "control_point.h"
45 #include "editor_regions.h"
46 #include "editor_cursors.h"
47 #include "midi_region_view.h"
53 using namespace ARDOUR;
57 using namespace Gtkmm2ext;
58 using namespace Editing;
60 struct TrackViewByPositionSorter
62 bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
63 return a->y_position() < b->y_position();
68 Editor::extend_selection_to_track (TimeAxisView& view)
70 if (selection->selected (&view)) {
71 /* already selected, do nothing */
75 if (selection->tracks.empty()) {
77 if (!selection->selected (&view)) {
78 selection->set (&view);
85 /* something is already selected, so figure out which range of things to add */
87 TrackViewList to_be_added;
88 TrackViewList sorted = track_views;
89 TrackViewByPositionSorter cmp;
90 bool passed_clicked = false;
95 /* figure out if we should go forward or backwards */
97 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
100 passed_clicked = true;
103 if (selection->selected (*i)) {
104 if (passed_clicked) {
113 passed_clicked = false;
117 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
120 passed_clicked = true;
124 if (passed_clicked) {
125 if ((*i)->hidden()) {
128 if (selection->selected (*i)) {
130 } else if (!(*i)->hidden()) {
131 to_be_added.push_back (*i);
138 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
141 passed_clicked = true;
145 if (passed_clicked) {
147 if ((*r)->hidden()) {
151 if (selection->selected (*r)) {
153 } else if (!(*r)->hidden()) {
154 to_be_added.push_back (*r);
160 if (!selection->selected (&view)) {
161 to_be_added.push_back (&view);
164 if (!to_be_added.empty()) {
165 selection->add (to_be_added);
173 Editor::select_all_tracks ()
175 TrackViewList visible_views;
176 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
177 if ((*i)->marked_for_display()) {
178 visible_views.push_back (*i);
181 PBD::Unwinder<bool> uw (_track_selection_change_without_scroll, true);
182 selection->set (visible_views);
185 /** Select clicked_axisview, unless there are no currently selected
186 * tracks, in which case nothing will happen unless `force' is true.
189 Editor::set_selected_track_as_side_effect (Selection::Operation op)
191 if (!clicked_axisview) {
195 PBD::Unwinder<bool> uw (_editor_track_selection_change_without_scroll, true);
197 RouteGroup* group = NULL;
198 if (clicked_routeview) {
199 group = clicked_routeview->route()->route_group();
203 case Selection::Toggle:
204 if (selection->selected (clicked_axisview)) {
205 if (group && group->is_active()) {
206 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
207 if ((*i)->route_group() == group) {
208 selection->remove(*i);
212 selection->remove (clicked_axisview);
215 if (group && group->is_active()) {
216 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
217 if ((*i)->route_group() == group) {
222 selection->add (clicked_axisview);
228 if (group && group->is_active()) {
229 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
230 if ((*i)->route_group() == group) {
235 selection->add (clicked_axisview);
241 if (group && group->is_active()) {
242 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
243 if ((*i)->route_group() == group) {
248 selection->set (clicked_axisview);
252 case Selection::Extend:
259 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
261 begin_reversible_selection_op (X_("Set Selected Track"));
264 case Selection::Toggle:
265 if (selection->selected (&view)) {
267 selection->remove (&view);
270 selection->add (&view);
275 selection->add (&view);
279 selection->set (&view);
282 case Selection::Extend:
283 extend_selection_to_track (view);
287 commit_reversible_selection_op ();
291 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
293 if (!clicked_routeview) {
301 set_selected_track (*clicked_routeview, op, no_remove);
305 Editor::set_selected_control_point_from_click (bool press, Selection::Operation op)
307 if (!clicked_control_point) {
315 if (!selection->selected (clicked_control_point)) {
316 selection->set (clicked_control_point);
319 /* clicked on an already selected point */
323 if (selection->points.size() > 1) {
324 selection->set (clicked_control_point);
333 selection->add (clicked_control_point);
337 case Selection::Toggle:
339 /* This is a bit of a hack; if we Primary-Click-Drag a control
340 point (for push drag) we want the point we clicked on to be
341 selected, otherwise we end up confusingly dragging an
342 unselected point. So here we ensure that the point is selected
343 after the press, and if we subsequently get a release (meaning no
344 drag occurred) we set things up so that the toggle has happened.
346 if (press && !selection->selected (clicked_control_point)) {
347 /* This is the button press, and the control point is not selected; make it so,
348 in case this press leads to a drag. Also note that having done this, we don't
349 need to toggle again on release.
351 selection->toggle (clicked_control_point);
352 _control_point_toggled_on_press = true;
354 } else if (!press && !_control_point_toggled_on_press) {
355 /* This is the release, and the point wasn't toggled on the press, so do it now */
356 selection->toggle (clicked_control_point);
360 _control_point_toggled_on_press = false;
363 case Selection::Extend:
372 Editor::get_onscreen_tracks (TrackViewList& tvl)
374 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
375 if ((*i)->y_position() < _visible_canvas_height) {
381 /** Call a slot for a given `basis' track and also for any track that is in the same
382 * active route group with a particular set of properties.
384 * @param sl Slot to call.
385 * @param basis Basis track.
386 * @param prop Properties that active edit groups must share to be included in the map.
390 Editor::mapover_tracks (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
392 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
394 if (route_basis == 0) {
398 set<RouteTimeAxisView*> tracks;
399 tracks.insert (route_basis);
401 RouteGroup* group = route_basis->route()->route_group();
403 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id)) {
405 /* the basis is a member of an active route group, with the appropriate
406 properties; find other members */
408 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
409 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
410 if (v && v->route()->route_group() == group) {
417 uint32_t const sz = tracks.size ();
419 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
424 /** Call a slot for a given `basis' track and also for any track that is in the same
425 * active route group with a particular set of properties.
427 * @param sl Slot to call.
428 * @param basis Basis track.
429 * @param prop Properties that active edit groups must share to be included in the map.
433 Editor::mapover_tracks_with_unique_playlists (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
435 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
436 set<boost::shared_ptr<Playlist> > playlists;
438 if (route_basis == 0) {
442 set<RouteTimeAxisView*> tracks;
443 tracks.insert (route_basis);
445 RouteGroup* group = route_basis->route()->route_group(); // could be null, not a problem
447 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id)) {
449 /* the basis is a member of an active route group, with the appropriate
450 properties; find other members */
452 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
453 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
455 if (v && v->route()->route_group() == group) {
457 boost::shared_ptr<Track> t = v->track();
459 if (playlists.insert (t->playlist()).second) {
460 /* haven't seen this playlist yet */
464 /* not actually a "Track", but a timeaxis view that
465 we should mapover anyway.
474 uint32_t const sz = tracks.size ();
476 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
482 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
484 boost::shared_ptr<Playlist> pl;
485 vector<boost::shared_ptr<Region> > results;
487 boost::shared_ptr<Track> tr;
489 if ((tr = tv.track()) == 0) {
494 if (&tv == &basis->get_time_axis_view()) {
495 /* looking in same track as the original */
499 if ((pl = tr->playlist()) != 0) {
500 pl->get_equivalent_regions (basis->region(), results);
503 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
504 if ((marv = tv.view()->find_view (*ir)) != 0) {
505 all_equivs->push_back (marv);
511 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, PBD::PropertyID property) const
513 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);
515 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
517 equivalent_regions.push_back (basis);
521 Editor::get_equivalent_regions (RegionSelection & basis, PBD::PropertyID prop) const
523 RegionSelection equivalent;
525 for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
527 vector<RegionView*> eq;
529 mapover_tracks_with_unique_playlists (
530 sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
531 &(*i)->get_time_axis_view(), prop);
533 for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
544 Editor::get_regionview_count_from_region_list (boost::shared_ptr<Region> region)
546 int region_count = 0;
548 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
550 RouteTimeAxisView* tatv;
552 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
554 boost::shared_ptr<Playlist> pl;
555 vector<boost::shared_ptr<Region> > results;
557 boost::shared_ptr<Track> tr;
559 if ((tr = tatv->track()) == 0) {
564 if ((pl = (tr->playlist())) != 0) {
565 pl->get_region_list_equivalent_regions (region, results);
568 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
569 if ((marv = tatv->view()->find_view (*ir)) != 0) {
582 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op)
584 vector<RegionView*> all_equivalent_regions;
587 if (!clicked_regionview || !clicked_routeview) {
592 button_release_can_deselect = false;
595 if (op == Selection::Toggle || op == Selection::Set) {
598 case Selection::Toggle:
599 if (selection->selected (clicked_regionview)) {
602 /* whatever was clicked was selected already; do nothing here but allow
603 the button release to deselect it
606 button_release_can_deselect = true;
609 if (button_release_can_deselect) {
611 /* just remove this one region, but only on a permitted button release */
613 selection->remove (clicked_regionview);
616 /* no more deselect action on button release till a new press
617 finds an already selected object.
620 button_release_can_deselect = false;
628 if (selection->selected (clicked_routeview)) {
629 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
631 all_equivalent_regions.push_back (clicked_regionview);
634 /* add all the equivalent regions, but only on button press */
636 if (!all_equivalent_regions.empty()) {
640 selection->add (all_equivalent_regions);
646 if (!selection->selected (clicked_regionview)) {
647 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
648 selection->set (all_equivalent_regions);
651 /* clicked on an already selected region */
655 if (selection->regions.size() > 1) {
656 /* collapse region selection down to just this one region (and its equivalents) */
657 get_equivalent_regions(clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
658 selection->set(all_equivalent_regions);
670 } else if (op == Selection::Extend) {
672 list<Selectable*> results;
673 samplepos_t last_sample;
674 samplepos_t first_sample;
675 bool same_track = false;
677 /* 1. find the last selected regionview in the track that was clicked in */
680 first_sample = max_samplepos;
682 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
683 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
685 if ((*x)->region()->last_sample() > last_sample) {
686 last_sample = (*x)->region()->last_sample();
689 if ((*x)->region()->first_sample() < first_sample) {
690 first_sample = (*x)->region()->first_sample();
699 /* 2. figure out the boundaries for our search for new objects */
701 switch (clicked_regionview->region()->coverage (first_sample, last_sample)) {
702 case Evoral::OverlapNone:
703 if (last_sample < clicked_regionview->region()->first_sample()) {
704 first_sample = last_sample;
705 last_sample = clicked_regionview->region()->last_sample();
707 last_sample = first_sample;
708 first_sample = clicked_regionview->region()->first_sample();
712 case Evoral::OverlapExternal:
713 if (last_sample < clicked_regionview->region()->first_sample()) {
714 first_sample = last_sample;
715 last_sample = clicked_regionview->region()->last_sample();
717 last_sample = first_sample;
718 first_sample = clicked_regionview->region()->first_sample();
722 case Evoral::OverlapInternal:
723 if (last_sample < clicked_regionview->region()->first_sample()) {
724 first_sample = last_sample;
725 last_sample = clicked_regionview->region()->last_sample();
727 last_sample = first_sample;
728 first_sample = clicked_regionview->region()->first_sample();
732 case Evoral::OverlapStart:
733 case Evoral::OverlapEnd:
734 /* nothing to do except add clicked region to selection, since it
735 overlaps with the existing selection in this track.
742 /* click in a track that has no regions selected, so extend vertically
743 to pick out all regions that are defined by the existing selection
748 first_sample = clicked_regionview->region()->position();
749 last_sample = clicked_regionview->region()->last_sample();
751 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
752 if ((*i)->region()->position() < first_sample) {
753 first_sample = (*i)->region()->position();
755 if ((*i)->region()->last_sample() + 1 > last_sample) {
756 last_sample = (*i)->region()->last_sample();
761 /* 2. find all the tracks we should select in */
763 set<RouteTimeAxisView*> relevant_tracks;
765 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
766 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
768 relevant_tracks.insert (r);
772 set<RouteTimeAxisView*> already_in_selection;
774 if (relevant_tracks.empty()) {
776 /* no tracks selected .. thus .. if the
777 regionview we're in isn't selected
778 (i.e. we're about to extend to it), then
779 find all tracks between the this one and
783 if (!selection->selected (clicked_regionview)) {
785 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&clicked_regionview->get_time_axis_view());
789 /* add this track to the ones we will search */
791 relevant_tracks.insert (rtv);
793 /* find the track closest to this one that
794 already a selected region.
797 RouteTimeAxisView* closest = 0;
798 int distance = INT_MAX;
799 int key = rtv->route()->presentation_info().order ();
801 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
803 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
805 if (artv && artv != rtv) {
807 pair<set<RouteTimeAxisView*>::iterator,bool> result;
809 result = already_in_selection.insert (artv);
812 /* newly added to already_in_selection */
814 int d = artv->route()->presentation_info().order ();
818 if (abs (d) < distance) {
828 /* now add all tracks between that one and this one */
830 int okey = closest->route()->presentation_info().order ();
836 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
837 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
838 if (artv && artv != rtv) {
840 int k = artv->route()->presentation_info().order ();
842 if (k >= okey && k <= key) {
844 /* in range but don't add it if
845 it already has tracks selected.
846 this avoids odd selection
847 behaviour that feels wrong.
850 if (find (already_in_selection.begin(),
851 already_in_selection.end(),
852 artv) == already_in_selection.end()) {
854 relevant_tracks.insert (artv);
864 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
865 one that was clicked.
868 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
869 (*t)->get_selectables (first_sample, last_sample, -1.0, -1.0, results);
872 /* 4. convert to a vector of regions */
874 vector<RegionView*> regions;
876 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
879 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
880 regions.push_back (arv);
884 if (!regions.empty()) {
885 selection->add (regions);
887 } else if (selection->regions.empty() && !selection->selected (clicked_regionview)) {
888 /* ensure that at least the clicked regionview is selected. */
889 selection->set (clicked_regionview);
900 Editor::set_selection (std::list<Selectable*> s, Selection::Operation op)
905 begin_reversible_selection_op (X_("set selection"));
907 case Selection::Toggle:
908 selection->toggle (s);
913 case Selection::Extend:
921 commit_reversible_selection_op () ;
925 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
927 vector<RegionView*> all_equivalent_regions;
929 get_regions_corresponding_to (region, all_equivalent_regions, region->whole_file());
931 if (all_equivalent_regions.empty()) {
935 begin_reversible_selection_op (X_("set selected regions"));
938 case Selection::Toggle:
939 /* XXX this is not correct */
940 selection->toggle (all_equivalent_regions);
943 selection->set (all_equivalent_regions);
945 case Selection::Extend:
946 selection->add (all_equivalent_regions);
949 selection->add (all_equivalent_regions);
953 commit_reversible_selection_op () ;
957 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
960 boost::shared_ptr<Region> r (weak_r.lock());
966 if ((rv = sv->find_view (r)) == 0) {
970 /* don't reset the selection if its something other than
971 a single other region.
974 if (selection->regions.size() > 1) {
978 begin_reversible_selection_op (X_("set selected regions"));
982 commit_reversible_selection_op () ;
988 Editor::presentation_info_changed (PropertyChange const & what_changed)
990 uint32_t n_tracks = 0;
991 uint32_t n_busses = 0;
993 uint32_t n_routes = 0;
994 uint32_t n_stripables = 0;
996 /* We cannot ensure ordering of the handlers for
997 * PresentationInfo::Changed, so we have to do everything in order
998 * here, as a single handler.
1001 if (what_changed.contains (Properties::selected)) {
1002 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1003 (*i)->set_selected (false);
1004 (*i)->hide_selection ();
1008 /* STEP 1: set the GUI selection state (in which TimeAxisViews for the
1009 * currently selected stripable/controllable duples are found and added
1012 selection->core_selection_changed (what_changed);
1014 /* STEP 2: update TimeAxisView's knowledge of their selected state
1017 if (what_changed.contains (Properties::selected)) {
1019 StripableNotificationListPtr stripables (new StripableNotificationList);
1021 switch (selection->tracks.size()) {
1025 set_selected_mixer_strip (*(selection->tracks.back()));
1026 if (!_track_selection_change_without_scroll && !_editor_track_selection_change_without_scroll) {
1027 ensure_time_axis_view_is_visible (*(selection->tracks.back()), false);
1032 CoreSelection::StripableAutomationControls sc;
1033 _session->selection().get_stripables (sc);
1035 for (CoreSelection::StripableAutomationControls::const_iterator i = sc.begin(); i != sc.end(); ++i) {
1037 AxisView* av = axis_view_by_stripable ((*i).stripable);
1045 if (boost::dynamic_pointer_cast<Track> ((*i).stripable)) {
1048 } else if (boost::dynamic_pointer_cast<Route> ((*i).stripable)) {
1051 } else if (boost::dynamic_pointer_cast<VCA> ((*i).stripable)) {
1055 TimeAxisView* tav = dynamic_cast<TimeAxisView*> (av);
1059 continue; /* impossible */
1062 if (!(*i).controllable) {
1064 /* "parent" track selected */
1065 tav->set_selected (true);
1066 tav->reshow_selection (selection->time);
1070 /* possibly a child */
1072 TimeAxisView::Children c = tav->get_child_list ();
1074 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
1076 boost::shared_ptr<AutomationControl> control = (*j)->control ();
1078 if (control != (*i).controllable) {
1082 (*j)->set_selected (true);
1083 (*j)->reshow_selection (selection->time);
1087 stripables->push_back ((*i).stripable);
1090 ActionManager::set_sensitive (ActionManager::stripable_selection_sensitive_actions, (n_stripables > 0));
1091 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, (n_tracks > 0));
1092 ActionManager::set_sensitive (ActionManager::bus_selection_sensitive_actions, (n_busses > 0));
1093 ActionManager::set_sensitive (ActionManager::route_selection_sensitive_actions, (n_routes > 0));
1094 ActionManager::set_sensitive (ActionManager::vca_selection_sensitive_actions, (n_vcas > 0));
1096 sensitize_the_right_region_actions (false);
1098 /* STEP 4: notify control protocols */
1100 ControlProtocolManager::instance().stripable_selection_changed (stripables);
1102 if (sfbrowser && _session && !_session->deletion_in_progress()) {
1103 uint32_t audio_track_cnt = 0;
1104 uint32_t midi_track_cnt = 0;
1106 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
1107 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*x);
1110 if (atv->is_audio_track()) {
1115 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(*x);
1118 if (mtv->is_midi_track()) {
1125 sfbrowser->reset (audio_track_cnt, midi_track_cnt);
1129 /* STEP 4: update EditorRoutes treeview */
1133 soh.add (Properties::selected);
1134 soh.add (Properties::order);
1135 soh.add (Properties::hidden);
1137 if (what_changed.contains (soh)) {
1138 _routes->sync_treeview_from_presentation_info (what_changed);
1143 Editor::track_selection_changed ()
1145 /* reset paste count, so the plaste location doesn't get incremented
1146 * if we want to paste in the same place, but different track. */
1149 if ( _session->solo_selection_active() )
1150 play_solo_selection(false);
1154 Editor::time_selection_changed ()
1156 /* XXX this is superficially inefficient. Hide the selection in all
1157 * tracks, then show it in all selected tracks.
1159 * However, if you investigate what this actually does, it isn't
1160 * anywhere nearly as bad as it may appear. Remember: nothing is
1161 * redrawn or even recomputed during these two loops - that only
1162 * happens when we next render ...
1165 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1166 (*i)->hide_selection ();
1169 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1170 (*i)->show_selection (selection->time);
1173 if (selection->time.empty()) {
1174 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
1176 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
1179 /* propagate into backend, but only when there is no drag or we are at
1180 * the end of a drag, otherwise this is too expensive (could case a
1181 * locate per mouse motion event.
1184 if (_session && !_drags->active()) {
1185 if (selection->time.length() != 0) {
1186 _session->set_range_selection (selection->time.start(), selection->time.end_sample());
1188 _session->clear_range_selection ();
1193 /** Set all region actions to have a given sensitivity */
1195 Editor::sensitize_all_region_actions (bool s)
1197 Glib::ListHandle<Glib::RefPtr<Action> > all = _region_actions->get_actions ();
1199 for (Glib::ListHandle<Glib::RefPtr<Action> >::iterator i = all.begin(); i != all.end(); ++i) {
1200 (*i)->set_sensitive (s);
1203 _all_region_actions_sensitized = s;
1206 /** Sensitize region-based actions.
1208 * This method is called from whenever we leave the canvas, either by moving
1209 * the pointer out of it, or by popping up a context menu. See
1210 * Editor::{entered,left}_track_canvas() for details there.
1213 Editor::sensitize_the_right_region_actions (bool because_canvas_crossing)
1215 bool have_selection = false;
1216 bool have_entered = false;
1217 bool have_edit_point = false;
1218 bool have_selected_source = false;
1221 // std::cerr << "STRRA: crossing ? " << because_canvas_crossing << " within ? " << within_track_canvas
1224 if (!selection->regions.empty()) {
1225 have_selection = true;
1226 rs = selection->regions;
1229 if (entered_regionview) {
1230 have_entered = true;
1231 rs.add (entered_regionview);
1234 if ( _sources->get_single_selection() ) {
1235 have_selected_source = true;
1238 if (rs.empty() && !selection->tracks.empty()) {
1240 /* no selected regions, but some selected tracks.
1243 if (_edit_point == EditAtMouse) {
1244 if (!within_track_canvas) {
1245 /* pointer is not in canvas, so edit point is meaningless */
1246 have_edit_point = false;
1248 /* inside canvas. we don't know where the edit
1249 point will be when an action is invoked, but
1250 assume it could intersect with a region.
1252 have_edit_point = true;
1255 RegionSelection at_edit_point;
1256 samplepos_t const where = get_preferred_edit_position (Editing::EDIT_IGNORE_NONE, false, !within_track_canvas);
1257 get_regions_at (at_edit_point, where, selection->tracks);
1258 if (!at_edit_point.empty()) {
1259 have_edit_point = true;
1262 rs.insert (rs.end(), at_edit_point.begin(), at_edit_point.end());
1267 //std::cerr << "\tfinal have selection: " << have_selection
1268 // << " have entered " << have_entered
1269 // << " have edit point " << have_edit_point
1270 // << " EP = " << enum_2_string (_edit_point)
1273 typedef std::map<std::string,RegionAction> RegionActionMap;
1275 _ignore_region_action = true;
1277 for (RegionActionMap::iterator x = region_action_map.begin(); x != region_action_map.end(); ++x) {
1278 RegionActionTarget tgt = x->second.target;
1279 bool sensitive = false;
1281 if ((tgt & SelectedRegions) && have_selection) {
1283 } else if ((tgt & EnteredRegions) && have_entered) {
1285 } else if ((tgt & EditPointRegions) && have_edit_point) {
1287 } else if ((tgt & ListSelection) && have_selected_source ) {
1291 x->second.action->set_sensitive (sensitive);
1294 /* Look through the regions that are selected and make notes about what we have got */
1296 bool have_audio = false;
1297 bool have_multichannel_audio = false;
1298 bool have_midi = false;
1299 bool have_locked = false;
1300 bool have_unlocked = false;
1301 bool have_video_locked = false;
1302 bool have_video_unlocked = false;
1303 bool have_position_lock_style_audio = false;
1304 bool have_position_lock_style_music = false;
1305 bool have_muted = false;
1306 bool have_unmuted = false;
1307 bool have_opaque = false;
1308 bool have_non_opaque = false;
1309 bool have_not_at_natural_position = false;
1310 bool have_envelope_active = false;
1311 bool have_envelope_inactive = false;
1312 bool have_non_unity_scale_amplitude = false;
1313 bool have_compound_regions = false;
1314 bool have_inactive_fade_in = false;
1315 bool have_inactive_fade_out = false;
1316 bool have_active_fade_in = false;
1317 bool have_active_fade_out = false;
1318 bool have_transients = false;
1320 for (list<RegionView*>::const_iterator i = rs.begin(); i != rs.end(); ++i) {
1322 boost::shared_ptr<Region> r = (*i)->region ();
1323 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
1327 if (ar->n_channels() > 1) {
1328 have_multichannel_audio = true;
1332 if (boost::dynamic_pointer_cast<MidiRegion> (r)) {
1336 if (r->is_compound()) {
1337 have_compound_regions = true;
1343 have_unlocked = true;
1346 if (r->video_locked()) {
1347 have_video_locked = true;
1349 have_video_unlocked = true;
1352 if (r->position_lock_style() == MusicTime) {
1353 have_position_lock_style_music = true;
1355 have_position_lock_style_audio = true;
1361 have_unmuted = true;
1367 have_non_opaque = true;
1370 if (!r->at_natural_position()) {
1371 have_not_at_natural_position = true;
1374 if (r->has_transients ()){
1375 have_transients = true;
1379 if (ar->envelope_active()) {
1380 have_envelope_active = true;
1382 have_envelope_inactive = true;
1385 if (ar->scale_amplitude() != 1) {
1386 have_non_unity_scale_amplitude = true;
1389 if (ar->fade_in_active ()) {
1390 have_active_fade_in = true;
1392 have_inactive_fade_in = true;
1395 if (ar->fade_out_active ()) {
1396 have_active_fade_out = true;
1398 have_inactive_fade_out = true;
1403 _region_actions->get_action("split-region-at-transients")->set_sensitive (have_transients);
1405 if (rs.size() > 1) {
1406 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1407 _region_actions->get_action("show-region-properties")->set_sensitive (false);
1408 _region_actions->get_action("rename-region")->set_sensitive (false);
1410 /* XXX need to check whether there is than 1 per
1411 playlist, because otherwise this makes no sense.
1413 _region_actions->get_action("combine-regions")->set_sensitive (true);
1415 _region_actions->get_action("combine-regions")->set_sensitive (false);
1417 } else if (rs.size() == 1) {
1418 _region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
1419 _region_actions->get_action("close-region-gaps")->set_sensitive (false);
1420 _region_actions->get_action("combine-regions")->set_sensitive (false);
1423 if (!have_multichannel_audio) {
1424 _region_actions->get_action("split-multichannel-region")->set_sensitive (false);
1428 editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (false);
1429 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1430 _region_actions->get_action("quantize-region")->set_sensitive (false);
1431 _region_actions->get_action("legatize-region")->set_sensitive (false);
1432 _region_actions->get_action("remove-overlap")->set_sensitive (false);
1433 _region_actions->get_action("transform-region")->set_sensitive (false);
1434 _region_actions->get_action("fork-region")->set_sensitive (false);
1435 _region_actions->get_action("insert-patch-change-context")->set_sensitive (false);
1436 _region_actions->get_action("insert-patch-change")->set_sensitive (false);
1437 _region_actions->get_action("transpose-region")->set_sensitive (false);
1439 editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (true);
1440 /* others were already marked sensitive */
1443 /* ok, moving along... */
1445 if (have_compound_regions) {
1446 _region_actions->get_action("uncombine-regions")->set_sensitive (true);
1448 _region_actions->get_action("uncombine-regions")->set_sensitive (false);
1453 if (have_envelope_active && !have_envelope_inactive) {
1454 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active ();
1455 } else if (have_envelope_active && have_envelope_inactive) {
1456 // Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_inconsistent ();
1461 _region_actions->get_action("loudness-analyze-region")->set_sensitive (false);
1462 _region_actions->get_action("spectral-analyze-region")->set_sensitive (false);
1463 _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
1464 _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
1465 _region_actions->get_action("pitch-shift-region")->set_sensitive (false);
1466 _region_actions->get_action("strip-region-silence")->set_sensitive (false);
1467 _region_actions->get_action("show-rhythm-ferret")->set_sensitive (false);
1471 if (!have_non_unity_scale_amplitude || !have_audio) {
1472 _region_actions->get_action("reset-region-scale-amplitude")->set_sensitive (false);
1475 Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"));
1476 a->set_active (have_locked && !have_unlocked);
1477 if (have_locked && have_unlocked) {
1478 // a->set_inconsistent ();
1481 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-video-lock"));
1482 a->set_active (have_video_locked && !have_video_unlocked);
1483 if (have_video_locked && have_video_unlocked) {
1484 // a->set_inconsistent ();
1487 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
1488 a->set_active (have_position_lock_style_music && !have_position_lock_style_audio);
1490 vector<Widget*> proxies = a->get_proxies();
1491 for (vector<Widget*>::iterator p = proxies.begin(); p != proxies.end(); ++p) {
1492 Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (*p);
1494 cmi->set_inconsistent (have_position_lock_style_music && have_position_lock_style_audio);
1498 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"));
1499 a->set_active (have_muted && !have_unmuted);
1500 if (have_muted && have_unmuted) {
1501 // a->set_inconsistent ();
1504 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"));
1505 a->set_active (have_opaque && !have_non_opaque);
1506 if (have_opaque && have_non_opaque) {
1507 // a->set_inconsistent ();
1510 if (!have_not_at_natural_position) {
1511 _region_actions->get_action("naturalize-region")->set_sensitive (false);
1514 /* Todo: insert-region-from-source-list
1515 /* XXX: should also check that there is a track of the appropriate type for the selected region */
1517 if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
1518 _region_actions->get_action("insert-region-from-source-list")->set_sensitive (false);
1520 _region_actions->get_action("insert-region-from-source-list")->set_sensitive (true);
1524 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-in"));
1525 a->set_active (have_active_fade_in && !have_inactive_fade_in);
1526 if (have_active_fade_in && have_inactive_fade_in) {
1527 // a->set_inconsistent ();
1530 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-out"));
1531 a->set_active (have_active_fade_out && !have_inactive_fade_out);
1533 if (have_active_fade_out && have_inactive_fade_out) {
1534 // a->set_inconsistent ();
1537 bool const have_active_fade = have_active_fade_in || have_active_fade_out;
1538 bool const have_inactive_fade = have_inactive_fade_in || have_inactive_fade_out;
1540 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fades"));
1541 a->set_active (have_active_fade && !have_inactive_fade);
1543 if (have_active_fade && have_inactive_fade) {
1544 // a->set_inconsistent ();
1547 _ignore_region_action = false;
1549 _all_region_actions_sensitized = false;
1553 Editor::region_selection_changed ()
1555 _regions->block_change_connection (true);
1556 editor_regions_selection_changed_connection.block(true);
1558 if (_region_selection_change_updates_region_list) {
1559 _regions->unselect_all ();
1562 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1563 (*i)->set_selected_regionviews (selection->regions);
1566 if (_region_selection_change_updates_region_list) {
1567 _regions->set_selected (selection->regions);
1570 _regions->block_change_connection (false);
1571 editor_regions_selection_changed_connection.block(false);
1573 sensitize_the_right_region_actions (false);
1575 /* propagate into backend */
1578 if (!selection->regions.empty()) {
1579 _session->set_object_selection (selection->regions.start(), selection->regions.end_sample());
1581 _session->clear_object_selection ();
1585 if (_session->solo_selection_active()) {
1586 play_solo_selection(false);
1589 /* set nudge button color */
1590 if (! get_regions_from_selection_and_entered().empty()) {
1592 nudge_forward_button.set_name ("nudge button");
1593 nudge_backward_button.set_name ("nudge button");
1595 /* nudge marker or playhead */
1596 nudge_forward_button.set_name ("generic button");
1597 nudge_backward_button.set_name ("generic button");
1600 //there are a few global Editor->Select actions which select regions even if you aren't in Object mode.
1601 //if regions are selected, we must always force the mouse mode to Object...
1602 //... otherwise the user is confusingly left with selected regions that can't be manipulated.
1603 if (!selection->regions.empty()) {
1604 set_mouse_mode( MouseObject, false );
1609 Editor::point_selection_changed ()
1611 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1612 (*i)->set_selected_points (selection->points);
1617 Editor::select_all_in_track (Selection::Operation op)
1619 list<Selectable *> touched;
1621 if (!clicked_routeview) {
1625 begin_reversible_selection_op (X_("Select All in Track"));
1627 clicked_routeview->get_selectables (0, max_samplepos, 0, DBL_MAX, touched);
1630 case Selection::Toggle:
1631 selection->add (touched);
1633 case Selection::Set:
1634 selection->set (touched);
1636 case Selection::Extend:
1637 /* meaningless, because we're selecting everything */
1639 case Selection::Add:
1640 selection->add (touched);
1644 commit_reversible_selection_op ();
1648 Editor::select_all_internal_edit (Selection::Operation)
1650 bool selected = false;
1652 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1653 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1655 mrv->select_all_notes ();
1660 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(entered_regionview);
1662 mrv->select_all_notes ();
1670 Editor::select_all_objects (Selection::Operation op)
1672 list<Selectable *> touched;
1674 if (internal_editing() && select_all_internal_edit(op)) {
1675 return; // Selected notes
1680 if (selection->tracks.empty()) {
1683 ts = selection->tracks;
1686 for (TrackViewList::iterator iter = ts.begin(); iter != ts.end(); ++iter) {
1687 if ((*iter)->hidden()) {
1690 (*iter)->get_selectables (0, max_samplepos, 0, DBL_MAX, touched);
1693 begin_reversible_selection_op (X_("select all"));
1695 case Selection::Add:
1696 selection->add (touched);
1698 case Selection::Toggle:
1699 selection->toggle (touched);
1701 case Selection::Set:
1702 selection->set (touched);
1704 case Selection::Extend:
1705 /* meaningless, because we're selecting everything */
1708 commit_reversible_selection_op ();
1712 Editor::invert_selection_in_track ()
1714 list<Selectable *> touched;
1716 if (!clicked_routeview) {
1720 begin_reversible_selection_op (X_("Invert Selection in Track"));
1721 clicked_routeview->get_inverted_selectables (*selection, touched);
1722 selection->set (touched);
1723 commit_reversible_selection_op ();
1727 Editor::invert_selection ()
1730 if (internal_editing()) {
1731 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1732 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1734 mrv->invert_selection ();
1740 if (!selection->tracks.empty()) {
1742 TrackViewList inverted;
1744 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1745 if (!(*iter)->selected()) {
1746 inverted.push_back (*iter);
1750 begin_reversible_selection_op (X_("Invert Track Selection"));
1751 selection->set (inverted);
1752 commit_reversible_selection_op ();
1756 list<Selectable *> touched;
1758 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1759 if ((*iter)->hidden()) {
1762 (*iter)->get_inverted_selectables (*selection, touched);
1765 begin_reversible_selection_op (X_("Invert ObjectSelection"));
1766 selection->set (touched);
1767 commit_reversible_selection_op ();
1771 /** @param start Start time in session samples.
1772 * @param end End time in session samples.
1773 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
1774 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
1775 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
1776 * within the region are already selected.
1779 Editor::select_all_within (samplepos_t start, samplepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected)
1781 list<Selectable*> found;
1783 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1785 if ((*iter)->hidden()) {
1789 (*iter)->get_selectables (start, end, top, bot, found);
1792 if (found.empty()) {
1793 selection->clear_objects();
1794 selection->clear_time ();
1798 if (preserve_if_selected && op != Selection::Toggle) {
1799 list<Selectable*>::iterator i = found.begin();
1800 while (i != found.end() && (*i)->selected()) {
1804 if (i == found.end()) {
1809 begin_reversible_selection_op (X_("select all within"));
1811 case Selection::Add:
1812 selection->add (found);
1814 case Selection::Toggle:
1815 selection->toggle (found);
1817 case Selection::Set:
1818 selection->set (found);
1820 case Selection::Extend:
1821 /* not defined yet */
1825 commit_reversible_selection_op ();
1829 Editor::set_selection_from_region ()
1831 if (selection->regions.empty()) {
1835 /* find all the tracks that have selected regions */
1837 set<TimeAxisView*> tracks;
1839 for (RegionSelection::const_iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
1840 tracks.insert (&(*r)->get_time_axis_view());
1844 tvl.insert (tvl.end(), tracks.begin(), tracks.end());
1846 /* select range (this will clear the region selection) */
1848 selection->set (selection->regions.start(), selection->regions.end_sample());
1850 /* and select the tracks */
1852 selection->set (tvl);
1854 if (!get_smart_mode () || !(mouse_mode == Editing::MouseObject) ) {
1855 set_mouse_mode (Editing::MouseRange, false);
1860 Editor::set_selection_from_punch()
1864 if ((location = _session->locations()->auto_punch_location()) == 0) {
1868 set_selection_from_range (*location);
1872 Editor::set_selection_from_loop()
1876 if ((location = _session->locations()->auto_loop_location()) == 0) {
1879 set_selection_from_range (*location);
1883 Editor::set_selection_from_range (Location& loc)
1885 begin_reversible_selection_op (X_("set selection from range"));
1887 selection->set (loc.start(), loc.end());
1889 // if no tracks are selected, enable all tracks
1890 // (_something_ has to be selected for any range selection, otherwise the user won't see anything)
1891 if (selection->tracks.empty()) {
1892 select_all_tracks();
1895 commit_reversible_selection_op ();
1897 if (!get_smart_mode () || mouse_mode != Editing::MouseObject) {
1898 set_mouse_mode (MouseRange, false);
1903 Editor::select_all_selectables_using_time_selection ()
1905 list<Selectable *> touched;
1907 if (selection->time.empty()) {
1911 samplepos_t start = selection->time[clicked_selection].start;
1912 samplepos_t end = selection->time[clicked_selection].end;
1914 if (end - start < 1) {
1920 if (selection->tracks.empty()) {
1923 ts = &selection->tracks;
1926 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1927 if ((*iter)->hidden()) {
1930 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1933 begin_reversible_selection_op (X_("select all from range"));
1934 selection->set (touched);
1935 commit_reversible_selection_op ();
1940 Editor::select_all_selectables_using_punch()
1942 Location* location = _session->locations()->auto_punch_location();
1943 list<Selectable *> touched;
1945 if (location == 0 || (location->end() - location->start() <= 1)) {
1952 if (selection->tracks.empty()) {
1955 ts = &selection->tracks;
1958 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1959 if ((*iter)->hidden()) {
1962 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1964 begin_reversible_selection_op (X_("select all from punch"));
1965 selection->set (touched);
1966 commit_reversible_selection_op ();
1971 Editor::select_all_selectables_using_loop()
1973 Location* location = _session->locations()->auto_loop_location();
1974 list<Selectable *> touched;
1976 if (location == 0 || (location->end() - location->start() <= 1)) {
1983 if (selection->tracks.empty()) {
1986 ts = &selection->tracks;
1989 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1990 if ((*iter)->hidden()) {
1993 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1995 begin_reversible_selection_op (X_("select all from loop"));
1996 selection->set (touched);
1997 commit_reversible_selection_op ();
2002 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
2006 list<Selectable *> touched;
2009 start = cursor->current_sample();
2010 end = _session->current_end_sample();
2012 if (cursor->current_sample() > 0) {
2014 end = cursor->current_sample() - 1;
2020 if (internal_editing()) {
2021 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2022 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
2024 mrv->select_range (start, end);
2031 begin_reversible_selection_op (X_("select all after cursor"));
2033 begin_reversible_selection_op (X_("select all before cursor"));
2038 if (selection->tracks.empty()) {
2041 ts = &selection->tracks;
2044 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
2045 if ((*iter)->hidden()) {
2048 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
2050 selection->set (touched);
2051 commit_reversible_selection_op ();
2055 Editor::select_all_selectables_using_edit (bool after, bool from_context_menu)
2059 list<Selectable *> touched;
2062 start = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu);
2063 end = _session->current_end_sample();
2065 if ((end = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu)) > 1) {
2073 if (internal_editing()) {
2074 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2075 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
2076 mrv->select_range (start, end);
2082 begin_reversible_selection_op (X_("select all after edit"));
2084 begin_reversible_selection_op (X_("select all before edit"));
2089 if (selection->tracks.empty()) {
2092 ts = &selection->tracks;
2095 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
2096 if ((*iter)->hidden()) {
2099 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
2101 selection->set (touched);
2102 commit_reversible_selection_op ();
2106 Editor::select_all_selectables_between (bool within)
2110 list<Selectable *> touched;
2112 if (!get_edit_op_range (start, end)) {
2116 if (internal_editing()) {
2117 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2118 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
2119 mrv->select_range (start, end);
2126 if (selection->tracks.empty()) {
2129 ts = &selection->tracks;
2132 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
2133 if ((*iter)->hidden()) {
2136 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched, within);
2139 begin_reversible_selection_op (X_("Select all Selectables Between"));
2140 selection->set (touched);
2141 commit_reversible_selection_op ();
2145 Editor::select_range_between ()
2150 if (!selection->time.empty()) {
2151 selection->clear_time ();
2154 if (!get_edit_op_range (start, end)) {
2158 if (!get_smart_mode () || mouse_mode != Editing::MouseObject) {
2159 set_mouse_mode (MouseRange, false);
2162 begin_reversible_selection_op (X_("Select Range Between"));
2163 selection->set (start, end);
2164 commit_reversible_selection_op ();
2168 Editor::get_edit_op_range (samplepos_t& start, samplepos_t& end) const
2170 /* if an explicit range exists, use it */
2172 if ((mouse_mode == MouseRange || get_smart_mode()) && !selection->time.empty()) {
2173 /* we know that these are ordered */
2174 start = selection->time.start();
2175 end = selection->time.end_sample();
2185 Editor::deselect_all ()
2187 begin_reversible_selection_op (X_("Deselect All"));
2188 selection->clear ();
2189 commit_reversible_selection_op ();
2193 Editor::select_range (samplepos_t s, samplepos_t e)
2195 begin_reversible_selection_op (X_("Select Range"));
2196 selection->add (clicked_axisview);
2197 selection->time.clear ();
2198 long ret = selection->set (s, e);
2199 commit_reversible_selection_op ();