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 () ;
986 struct SelectionOrderSorter {
987 bool operator() (TimeAxisView const * const a, TimeAxisView const * const b) const {
988 boost::shared_ptr<Stripable> sa = a->stripable ();
989 boost::shared_ptr<Stripable> sb = b->stripable ();
999 return sa->presentation_info().selection_cnt() < sb->presentation_info().selection_cnt();
1004 Editor::presentation_info_changed (PropertyChange const & what_changed)
1006 uint32_t n_tracks = 0;
1007 uint32_t n_busses = 0;
1008 uint32_t n_vcas = 0;
1009 uint32_t n_routes = 0;
1010 uint32_t n_stripables = 0;
1012 /* We cannot ensure ordering of the handlers for
1013 * PresentationInfo::Changed, so we have to do everything in order
1014 * here, as a single handler.
1017 if (what_changed.contains (Properties::selected)) {
1018 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1019 (*i)->set_selected (false);
1020 (*i)->hide_selection ();
1024 /* STEP 1: set the GUI selection state (in which TimeAxisViews for the
1025 * currently selected stripable/controllable duples are found and added
1028 selection->core_selection_changed (what_changed);
1030 /* STEP 2: update TimeAxisView's knowledge of their selected state
1033 if (what_changed.contains (Properties::selected)) {
1035 StripableNotificationListPtr stripables (new StripableNotificationList);
1037 switch (selection->tracks.size()) {
1041 set_selected_mixer_strip (*(selection->tracks.back()));
1042 if (!_track_selection_change_without_scroll && !_editor_track_selection_change_without_scroll) {
1043 ensure_time_axis_view_is_visible (*(selection->tracks.back()), false);
1048 CoreSelection::StripableAutomationControls sc;
1049 _session->selection().get_stripables (sc);
1051 for (CoreSelection::StripableAutomationControls::const_iterator i = sc.begin(); i != sc.end(); ++i) {
1053 AxisView* av = axis_view_by_stripable ((*i).stripable);
1061 if (boost::dynamic_pointer_cast<Track> ((*i).stripable)) {
1064 } else if (boost::dynamic_pointer_cast<Route> ((*i).stripable)) {
1067 } else if (boost::dynamic_pointer_cast<VCA> ((*i).stripable)) {
1071 TimeAxisView* tav = dynamic_cast<TimeAxisView*> (av);
1075 continue; /* impossible */
1078 if (!(*i).controllable) {
1080 /* "parent" track selected */
1081 tav->set_selected (true);
1082 tav->reshow_selection (selection->time);
1086 /* possibly a child */
1088 TimeAxisView::Children c = tav->get_child_list ();
1090 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
1092 boost::shared_ptr<AutomationControl> control = (*j)->control ();
1094 if (control != (*i).controllable) {
1098 (*j)->set_selected (true);
1099 (*j)->reshow_selection (selection->time);
1103 stripables->push_back ((*i).stripable);
1106 ActionManager::set_sensitive (ActionManager::stripable_selection_sensitive_actions, (n_stripables > 0));
1107 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, (n_tracks > 0));
1108 ActionManager::set_sensitive (ActionManager::bus_selection_sensitive_actions, (n_busses > 0));
1109 ActionManager::set_sensitive (ActionManager::route_selection_sensitive_actions, (n_routes > 0));
1110 ActionManager::set_sensitive (ActionManager::vca_selection_sensitive_actions, (n_vcas > 0));
1112 sensitize_the_right_region_actions (false);
1114 /* STEP 4: notify control protocols */
1116 ControlProtocolManager::instance().stripable_selection_changed (stripables);
1118 if (sfbrowser && _session && !_session->deletion_in_progress()) {
1119 uint32_t audio_track_cnt = 0;
1120 uint32_t midi_track_cnt = 0;
1122 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
1123 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*x);
1126 if (atv->is_audio_track()) {
1131 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(*x);
1134 if (mtv->is_midi_track()) {
1141 sfbrowser->reset (audio_track_cnt, midi_track_cnt);
1145 /* STEP 4: update EditorRoutes treeview */
1149 soh.add (Properties::selected);
1150 soh.add (Properties::order);
1151 soh.add (Properties::hidden);
1153 if (what_changed.contains (soh)) {
1154 _routes->sync_treeview_from_presentation_info (what_changed);
1159 Editor::track_selection_changed ()
1161 cout << "resetting paste count" << endl;
1162 /* reset paste count, so the plaste location doesn't get incremented
1163 * if we want to paste in the same place, but different track. */
1166 if ( _session->solo_selection_active() )
1167 play_solo_selection(false);
1171 Editor::time_selection_changed ()
1173 /* XXX this is superficially inefficient. Hide the selection in all
1174 * tracks, then show it in all selected tracks.
1176 * However, if you investigate what this actually does, it isn't
1177 * anywhere nearly as bad as it may appear. Remember: nothing is
1178 * redrawn or even recomputed during these two loops - that only
1179 * happens when we next render ...
1182 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1183 (*i)->hide_selection ();
1186 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1187 (*i)->show_selection (selection->time);
1190 if (selection->time.empty()) {
1191 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
1193 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
1196 /* propagate into backend, but only when there is no drag or we are at
1197 * the end of a drag, otherwise this is too expensive (could case a
1198 * locate per mouse motion event.
1201 if (_session && !_drags->active()) {
1202 if (selection->time.length() != 0) {
1203 _session->set_range_selection (selection->time.start(), selection->time.end_sample());
1205 _session->clear_range_selection ();
1210 /** Set all region actions to have a given sensitivity */
1212 Editor::sensitize_all_region_actions (bool s)
1214 Glib::ListHandle<Glib::RefPtr<Action> > all = _region_actions->get_actions ();
1216 for (Glib::ListHandle<Glib::RefPtr<Action> >::iterator i = all.begin(); i != all.end(); ++i) {
1217 (*i)->set_sensitive (s);
1220 _all_region_actions_sensitized = s;
1223 /** Sensitize region-based actions.
1225 * This method is called from whenever we leave the canvas, either by moving
1226 * the pointer out of it, or by popping up a context menu. See
1227 * Editor::{entered,left}_track_canvas() for details there.
1230 Editor::sensitize_the_right_region_actions (bool because_canvas_crossing)
1232 bool have_selection = false;
1233 bool have_entered = false;
1234 bool have_edit_point = false;
1237 // std::cerr << "STRRA: crossing ? " << because_canvas_crossing << " within ? " << within_track_canvas
1240 if (!selection->regions.empty()) {
1241 have_selection = true;
1242 rs = selection->regions;
1245 if (entered_regionview) {
1246 have_entered = true;
1247 rs.add (entered_regionview);
1250 if (rs.empty() && !selection->tracks.empty()) {
1252 /* no selected regions, but some selected tracks.
1255 if (_edit_point == EditAtMouse) {
1256 if (!within_track_canvas) {
1257 /* pointer is not in canvas, so edit point is meaningless */
1258 have_edit_point = false;
1260 /* inside canvas. we don't know where the edit
1261 point will be when an action is invoked, but
1262 assume it could intersect with a region.
1264 have_edit_point = true;
1267 RegionSelection at_edit_point;
1268 samplepos_t const where = get_preferred_edit_position (Editing::EDIT_IGNORE_NONE, false, !within_track_canvas);
1269 get_regions_at (at_edit_point, where, selection->tracks);
1270 if (!at_edit_point.empty()) {
1271 have_edit_point = true;
1274 rs.insert (rs.end(), at_edit_point.begin(), at_edit_point.end());
1279 //std::cerr << "\tfinal have selection: " << have_selection
1280 // << " have entered " << have_entered
1281 // << " have edit point " << have_edit_point
1282 // << " EP = " << enum_2_string (_edit_point)
1285 typedef std::map<std::string,RegionAction> RegionActionMap;
1287 _ignore_region_action = true;
1289 for (RegionActionMap::iterator x = region_action_map.begin(); x != region_action_map.end(); ++x) {
1290 RegionActionTarget tgt = x->second.target;
1291 bool sensitive = false;
1293 if ((tgt & SelectedRegions) && have_selection) {
1295 } else if ((tgt & EnteredRegions) && have_entered) {
1297 } else if ((tgt & EditPointRegions) && have_edit_point) {
1301 x->second.action->set_sensitive (sensitive);
1304 /* Look through the regions that are selected and make notes about what we have got */
1306 bool have_audio = false;
1307 bool have_multichannel_audio = false;
1308 bool have_midi = false;
1309 bool have_locked = false;
1310 bool have_unlocked = false;
1311 bool have_video_locked = false;
1312 bool have_video_unlocked = false;
1313 bool have_position_lock_style_audio = false;
1314 bool have_position_lock_style_music = false;
1315 bool have_muted = false;
1316 bool have_unmuted = false;
1317 bool have_opaque = false;
1318 bool have_non_opaque = false;
1319 bool have_not_at_natural_position = false;
1320 bool have_envelope_active = false;
1321 bool have_envelope_inactive = false;
1322 bool have_non_unity_scale_amplitude = false;
1323 bool have_compound_regions = false;
1324 bool have_inactive_fade_in = false;
1325 bool have_inactive_fade_out = false;
1326 bool have_active_fade_in = false;
1327 bool have_active_fade_out = false;
1328 bool have_transients = false;
1330 for (list<RegionView*>::const_iterator i = rs.begin(); i != rs.end(); ++i) {
1332 boost::shared_ptr<Region> r = (*i)->region ();
1333 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
1337 if (ar->n_channels() > 1) {
1338 have_multichannel_audio = true;
1342 if (boost::dynamic_pointer_cast<MidiRegion> (r)) {
1346 if (r->is_compound()) {
1347 have_compound_regions = true;
1353 have_unlocked = true;
1356 if (r->video_locked()) {
1357 have_video_locked = true;
1359 have_video_unlocked = true;
1362 if (r->position_lock_style() == MusicTime) {
1363 have_position_lock_style_music = true;
1365 have_position_lock_style_audio = true;
1371 have_unmuted = true;
1377 have_non_opaque = true;
1380 if (!r->at_natural_position()) {
1381 have_not_at_natural_position = true;
1384 if (r->has_transients ()){
1385 have_transients = true;
1389 if (ar->envelope_active()) {
1390 have_envelope_active = true;
1392 have_envelope_inactive = true;
1395 if (ar->scale_amplitude() != 1) {
1396 have_non_unity_scale_amplitude = true;
1399 if (ar->fade_in_active ()) {
1400 have_active_fade_in = true;
1402 have_inactive_fade_in = true;
1405 if (ar->fade_out_active ()) {
1406 have_active_fade_out = true;
1408 have_inactive_fade_out = true;
1413 _region_actions->get_action("split-region-at-transients")->set_sensitive (have_transients);
1415 if (rs.size() > 1) {
1416 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1417 _region_actions->get_action("show-region-properties")->set_sensitive (false);
1418 _region_actions->get_action("rename-region")->set_sensitive (false);
1420 /* XXX need to check whether there is than 1 per
1421 playlist, because otherwise this makes no sense.
1423 _region_actions->get_action("combine-regions")->set_sensitive (true);
1425 _region_actions->get_action("combine-regions")->set_sensitive (false);
1427 } else if (rs.size() == 1) {
1428 _region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
1429 _region_actions->get_action("close-region-gaps")->set_sensitive (false);
1430 _region_actions->get_action("combine-regions")->set_sensitive (false);
1433 if (!have_multichannel_audio) {
1434 _region_actions->get_action("split-multichannel-region")->set_sensitive (false);
1438 editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (false);
1439 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1440 _region_actions->get_action("quantize-region")->set_sensitive (false);
1441 _region_actions->get_action("legatize-region")->set_sensitive (false);
1442 _region_actions->get_action("remove-overlap")->set_sensitive (false);
1443 _region_actions->get_action("transform-region")->set_sensitive (false);
1444 _region_actions->get_action("fork-region")->set_sensitive (false);
1445 _region_actions->get_action("insert-patch-change-context")->set_sensitive (false);
1446 _region_actions->get_action("insert-patch-change")->set_sensitive (false);
1447 _region_actions->get_action("transpose-region")->set_sensitive (false);
1449 editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (true);
1450 /* others were already marked sensitive */
1453 /* ok, moving along... */
1455 if (have_compound_regions) {
1456 _region_actions->get_action("uncombine-regions")->set_sensitive (true);
1458 _region_actions->get_action("uncombine-regions")->set_sensitive (false);
1463 if (have_envelope_active && !have_envelope_inactive) {
1464 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active ();
1465 } else if (have_envelope_active && have_envelope_inactive) {
1466 // Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_inconsistent ();
1471 _region_actions->get_action("loudness-analyze-region")->set_sensitive (false);
1472 _region_actions->get_action("spectral-analyze-region")->set_sensitive (false);
1473 _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
1474 _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
1475 _region_actions->get_action("pitch-shift-region")->set_sensitive (false);
1476 _region_actions->get_action("strip-region-silence")->set_sensitive (false);
1477 _region_actions->get_action("show-rhythm-ferret")->set_sensitive (false);
1481 if (!have_non_unity_scale_amplitude || !have_audio) {
1482 _region_actions->get_action("reset-region-scale-amplitude")->set_sensitive (false);
1485 Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"));
1486 a->set_active (have_locked && !have_unlocked);
1487 if (have_locked && have_unlocked) {
1488 // a->set_inconsistent ();
1491 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-video-lock"));
1492 a->set_active (have_video_locked && !have_video_unlocked);
1493 if (have_video_locked && have_video_unlocked) {
1494 // a->set_inconsistent ();
1497 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
1498 a->set_active (have_position_lock_style_music && !have_position_lock_style_audio);
1500 vector<Widget*> proxies = a->get_proxies();
1501 for (vector<Widget*>::iterator p = proxies.begin(); p != proxies.end(); ++p) {
1502 Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (*p);
1504 cmi->set_inconsistent (have_position_lock_style_music && have_position_lock_style_audio);
1508 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"));
1509 a->set_active (have_muted && !have_unmuted);
1510 if (have_muted && have_unmuted) {
1511 // a->set_inconsistent ();
1514 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"));
1515 a->set_active (have_opaque && !have_non_opaque);
1516 if (have_opaque && have_non_opaque) {
1517 // a->set_inconsistent ();
1520 if (!have_not_at_natural_position) {
1521 _region_actions->get_action("naturalize-region")->set_sensitive (false);
1524 /* XXX: should also check that there is a track of the appropriate type for the selected region */
1525 if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
1526 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (false);
1528 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (true);
1531 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-in"));
1532 a->set_active (have_active_fade_in && !have_inactive_fade_in);
1533 if (have_active_fade_in && have_inactive_fade_in) {
1534 // a->set_inconsistent ();
1537 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-out"));
1538 a->set_active (have_active_fade_out && !have_inactive_fade_out);
1540 if (have_active_fade_out && have_inactive_fade_out) {
1541 // a->set_inconsistent ();
1544 bool const have_active_fade = have_active_fade_in || have_active_fade_out;
1545 bool const have_inactive_fade = have_inactive_fade_in || have_inactive_fade_out;
1547 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fades"));
1548 a->set_active (have_active_fade && !have_inactive_fade);
1550 if (have_active_fade && have_inactive_fade) {
1551 // a->set_inconsistent ();
1554 _ignore_region_action = false;
1556 _all_region_actions_sensitized = false;
1560 Editor::region_selection_changed ()
1562 _regions->block_change_connection (true);
1563 editor_regions_selection_changed_connection.block(true);
1565 if (_region_selection_change_updates_region_list) {
1566 _regions->unselect_all ();
1569 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1570 (*i)->set_selected_regionviews (selection->regions);
1573 if (_region_selection_change_updates_region_list) {
1574 _regions->set_selected (selection->regions);
1577 _regions->block_change_connection (false);
1578 editor_regions_selection_changed_connection.block(false);
1580 sensitize_the_right_region_actions (false);
1582 /* propagate into backend */
1585 if (!selection->regions.empty()) {
1586 _session->set_object_selection (selection->regions.start(), selection->regions.end_sample());
1588 _session->clear_object_selection ();
1592 if ( _session->solo_selection_active() )
1593 play_solo_selection(false);
1597 Editor::point_selection_changed ()
1599 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1600 (*i)->set_selected_points (selection->points);
1605 Editor::select_all_in_track (Selection::Operation op)
1607 list<Selectable *> touched;
1609 if (!clicked_routeview) {
1613 begin_reversible_selection_op (X_("Select All in Track"));
1615 clicked_routeview->get_selectables (0, max_samplepos, 0, DBL_MAX, touched);
1618 case Selection::Toggle:
1619 selection->add (touched);
1621 case Selection::Set:
1622 selection->set (touched);
1624 case Selection::Extend:
1625 /* meaningless, because we're selecting everything */
1627 case Selection::Add:
1628 selection->add (touched);
1632 commit_reversible_selection_op ();
1636 Editor::select_all_internal_edit (Selection::Operation)
1638 bool selected = false;
1640 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1641 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1643 mrv->select_all_notes ();
1648 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(entered_regionview);
1650 mrv->select_all_notes ();
1658 Editor::select_all_objects (Selection::Operation op)
1660 list<Selectable *> touched;
1662 if (internal_editing() && select_all_internal_edit(op)) {
1663 return; // Selected notes
1668 if (selection->tracks.empty()) {
1671 ts = selection->tracks;
1674 for (TrackViewList::iterator iter = ts.begin(); iter != ts.end(); ++iter) {
1675 if ((*iter)->hidden()) {
1678 (*iter)->get_selectables (0, max_samplepos, 0, DBL_MAX, touched);
1681 begin_reversible_selection_op (X_("select all"));
1683 case Selection::Add:
1684 selection->add (touched);
1686 case Selection::Toggle:
1687 selection->toggle (touched);
1689 case Selection::Set:
1690 selection->set (touched);
1692 case Selection::Extend:
1693 /* meaningless, because we're selecting everything */
1696 commit_reversible_selection_op ();
1700 Editor::invert_selection_in_track ()
1702 list<Selectable *> touched;
1704 if (!clicked_routeview) {
1708 begin_reversible_selection_op (X_("Invert Selection in Track"));
1709 clicked_routeview->get_inverted_selectables (*selection, touched);
1710 selection->set (touched);
1711 commit_reversible_selection_op ();
1715 Editor::invert_selection ()
1717 list<Selectable *> touched;
1719 if (internal_editing()) {
1720 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1721 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1723 mrv->invert_selection ();
1729 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1730 if ((*iter)->hidden()) {
1733 (*iter)->get_inverted_selectables (*selection, touched);
1736 begin_reversible_selection_op (X_("Invert Selection"));
1737 selection->set (touched);
1738 commit_reversible_selection_op ();
1741 /** @param start Start time in session samples.
1742 * @param end End time in session samples.
1743 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
1744 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
1745 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
1746 * within the region are already selected.
1749 Editor::select_all_within (samplepos_t start, samplepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected)
1751 list<Selectable*> found;
1753 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1755 if ((*iter)->hidden()) {
1759 (*iter)->get_selectables (start, end, top, bot, found);
1762 if (found.empty()) {
1763 selection->clear_objects();
1764 selection->clear_time ();
1768 if (preserve_if_selected && op != Selection::Toggle) {
1769 list<Selectable*>::iterator i = found.begin();
1770 while (i != found.end() && (*i)->selected()) {
1774 if (i == found.end()) {
1779 begin_reversible_selection_op (X_("select all within"));
1781 case Selection::Add:
1782 selection->add (found);
1784 case Selection::Toggle:
1785 selection->toggle (found);
1787 case Selection::Set:
1788 selection->set (found);
1790 case Selection::Extend:
1791 /* not defined yet */
1795 commit_reversible_selection_op ();
1799 Editor::set_selection_from_region ()
1801 if (selection->regions.empty()) {
1805 /* find all the tracks that have selected regions */
1807 set<TimeAxisView*> tracks;
1809 for (RegionSelection::const_iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
1810 tracks.insert (&(*r)->get_time_axis_view());
1814 tvl.insert (tvl.end(), tracks.begin(), tracks.end());
1816 /* select range (this will clear the region selection) */
1818 selection->set (selection->regions.start(), selection->regions.end_sample());
1820 /* and select the tracks */
1822 selection->set (tvl);
1824 if (!get_smart_mode () || !(mouse_mode == Editing::MouseObject) ) {
1825 set_mouse_mode (Editing::MouseRange, false);
1830 Editor::set_selection_from_punch()
1834 if ((location = _session->locations()->auto_punch_location()) == 0) {
1838 set_selection_from_range (*location);
1842 Editor::set_selection_from_loop()
1846 if ((location = _session->locations()->auto_loop_location()) == 0) {
1849 set_selection_from_range (*location);
1853 Editor::set_selection_from_range (Location& loc)
1855 begin_reversible_selection_op (X_("set selection from range"));
1857 selection->set (loc.start(), loc.end());
1859 // if no tracks are selected, enable all tracks
1860 // (_something_ has to be selected for any range selection, otherwise the user won't see anything)
1861 if (selection->tracks.empty()) {
1862 select_all_tracks();
1865 commit_reversible_selection_op ();
1867 if (!get_smart_mode () || mouse_mode != Editing::MouseObject) {
1868 set_mouse_mode (MouseRange, false);
1873 Editor::select_all_selectables_using_time_selection ()
1875 list<Selectable *> touched;
1877 if (selection->time.empty()) {
1881 samplepos_t start = selection->time[clicked_selection].start;
1882 samplepos_t end = selection->time[clicked_selection].end;
1884 if (end - start < 1) {
1890 if (selection->tracks.empty()) {
1893 ts = &selection->tracks;
1896 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1897 if ((*iter)->hidden()) {
1900 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1903 begin_reversible_selection_op (X_("select all from range"));
1904 selection->set (touched);
1905 commit_reversible_selection_op ();
1910 Editor::select_all_selectables_using_punch()
1912 Location* location = _session->locations()->auto_punch_location();
1913 list<Selectable *> touched;
1915 if (location == 0 || (location->end() - location->start() <= 1)) {
1922 if (selection->tracks.empty()) {
1925 ts = &selection->tracks;
1928 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1929 if ((*iter)->hidden()) {
1932 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1934 begin_reversible_selection_op (X_("select all from punch"));
1935 selection->set (touched);
1936 commit_reversible_selection_op ();
1941 Editor::select_all_selectables_using_loop()
1943 Location* location = _session->locations()->auto_loop_location();
1944 list<Selectable *> touched;
1946 if (location == 0 || (location->end() - location->start() <= 1)) {
1953 if (selection->tracks.empty()) {
1956 ts = &selection->tracks;
1959 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1960 if ((*iter)->hidden()) {
1963 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1965 begin_reversible_selection_op (X_("select all from loop"));
1966 selection->set (touched);
1967 commit_reversible_selection_op ();
1972 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1976 list<Selectable *> touched;
1979 start = cursor->current_sample();
1980 end = _session->current_end_sample();
1982 if (cursor->current_sample() > 0) {
1984 end = cursor->current_sample() - 1;
1990 if (internal_editing()) {
1991 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1992 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1994 mrv->select_range (start, end);
2001 begin_reversible_selection_op (X_("select all after cursor"));
2003 begin_reversible_selection_op (X_("select all before cursor"));
2008 if (selection->tracks.empty()) {
2011 ts = &selection->tracks;
2014 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
2015 if ((*iter)->hidden()) {
2018 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
2020 selection->set (touched);
2021 commit_reversible_selection_op ();
2025 Editor::select_all_selectables_using_edit (bool after, bool from_context_menu)
2029 list<Selectable *> touched;
2032 start = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu);
2033 end = _session->current_end_sample();
2035 if ((end = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu)) > 1) {
2043 if (internal_editing()) {
2044 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2045 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
2046 mrv->select_range (start, end);
2052 begin_reversible_selection_op (X_("select all after edit"));
2054 begin_reversible_selection_op (X_("select all before edit"));
2059 if (selection->tracks.empty()) {
2062 ts = &selection->tracks;
2065 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
2066 if ((*iter)->hidden()) {
2069 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
2071 selection->set (touched);
2072 commit_reversible_selection_op ();
2076 Editor::select_all_selectables_between (bool within)
2080 list<Selectable *> touched;
2082 if (!get_edit_op_range (start, end)) {
2086 if (internal_editing()) {
2087 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2088 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
2089 mrv->select_range (start, end);
2096 if (selection->tracks.empty()) {
2099 ts = &selection->tracks;
2102 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
2103 if ((*iter)->hidden()) {
2106 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched, within);
2109 begin_reversible_selection_op (X_("Select all Selectables Between"));
2110 selection->set (touched);
2111 commit_reversible_selection_op ();
2115 Editor::select_range_between ()
2120 if (!selection->time.empty()) {
2121 selection->clear_time ();
2124 if (!get_edit_op_range (start, end)) {
2128 if (!get_smart_mode () || mouse_mode != Editing::MouseObject) {
2129 set_mouse_mode (MouseRange, false);
2132 begin_reversible_selection_op (X_("Select Range Between"));
2133 selection->set (start, end);
2134 commit_reversible_selection_op ();
2138 Editor::get_edit_op_range (samplepos_t& start, samplepos_t& end) const
2143 /* if an explicit range exists, use it */
2145 if ((mouse_mode == MouseRange || get_smart_mode()) && !selection->time.empty()) {
2146 /* we know that these are ordered */
2147 start = selection->time.start();
2148 end = selection->time.end_sample();
2156 // if (!mouse_sample (m, ignored)) {
2157 // /* mouse is not in a canvas, try playhead+selected marker.
2158 // this is probably most true when using menus.
2161 // if (selection->markers.empty()) {
2165 // start = selection->markers.front()->position();
2166 // end = _session->audible_sample();
2170 // switch (_edit_point) {
2171 // case EditAtPlayhead:
2172 // if (selection->markers.empty()) {
2173 // /* use mouse + playhead */
2175 // end = _session->audible_sample();
2177 // /* use playhead + selected marker */
2178 // start = _session->audible_sample();
2179 // end = selection->markers.front()->position();
2183 // case EditAtMouse:
2184 // /* use mouse + selected marker */
2185 // if (selection->markers.empty()) {
2187 // end = _session->audible_sample();
2189 // start = selection->markers.front()->position();
2194 // case EditAtSelectedMarker:
2195 // /* use mouse + selected marker */
2196 // if (selection->markers.empty()) {
2198 // MessageDialog win (_("No edit range defined"),
2203 // win.set_secondary_text (
2204 // _("the edit point is Selected Marker\nbut there is no selected marker."));
2207 // win.set_default_response (RESPONSE_CLOSE);
2208 // win.set_position (Gtk::WIN_POS_MOUSE);
2213 // return false; // NO RANGE
2215 // start = selection->markers.front()->position();
2221 // if (start == end) {
2225 // if (start > end) {
2226 // swap (start, end);
2229 /* turn range into one delimited by start...end,
2239 Editor::deselect_all ()
2241 begin_reversible_selection_op (X_("Deselect All"));
2242 selection->clear ();
2243 commit_reversible_selection_op ();
2247 Editor::select_range (samplepos_t s, samplepos_t e)
2249 begin_reversible_selection_op (X_("Select Range"));
2250 selection->add (clicked_axisview);
2251 selection->time.clear ();
2252 long ret = selection->set (s, e);
2253 commit_reversible_selection_op ();