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"
35 #include "editor_drag.h"
36 #include "editor_routes.h"
38 #include "audio_time_axis.h"
39 #include "audio_region_view.h"
40 #include "audio_streamview.h"
41 #include "automation_line.h"
42 #include "control_point.h"
43 #include "editor_regions.h"
44 #include "editor_cursors.h"
45 #include "midi_region_view.h"
51 using namespace ARDOUR;
55 using namespace Gtkmm2ext;
56 using namespace Editing;
58 struct TrackViewByPositionSorter
60 bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
61 return a->y_position() < b->y_position();
66 Editor::extend_selection_to_track (TimeAxisView& view)
68 if (selection->selected (&view)) {
69 /* already selected, do nothing */
73 if (selection->tracks.empty()) {
75 if (!selection->selected (&view)) {
76 selection->set (&view);
83 /* something is already selected, so figure out which range of things to add */
85 TrackViewList to_be_added;
86 TrackViewList sorted = track_views;
87 TrackViewByPositionSorter cmp;
88 bool passed_clicked = false;
93 /* figure out if we should go forward or backwards */
95 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
98 passed_clicked = true;
101 if (selection->selected (*i)) {
102 if (passed_clicked) {
111 passed_clicked = false;
115 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
118 passed_clicked = true;
122 if (passed_clicked) {
123 if ((*i)->hidden()) {
126 if (selection->selected (*i)) {
128 } else if (!(*i)->hidden()) {
129 to_be_added.push_back (*i);
136 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
139 passed_clicked = true;
143 if (passed_clicked) {
145 if ((*r)->hidden()) {
149 if (selection->selected (*r)) {
151 } else if (!(*r)->hidden()) {
152 to_be_added.push_back (*r);
158 if (!selection->selected (&view)) {
159 to_be_added.push_back (&view);
162 if (!to_be_added.empty()) {
163 selection->add (to_be_added);
171 Editor::select_all_tracks ()
173 TrackViewList visible_views;
174 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
175 if ((*i)->marked_for_display()) {
176 visible_views.push_back (*i);
179 PBD::Unwinder<bool> uw (_track_selection_change_without_scroll, true);
180 selection->set (visible_views);
183 /** Select clicked_axisview, unless there are no currently selected
184 * tracks, in which case nothing will happen unless `force' is true.
187 Editor::set_selected_track_as_side_effect (Selection::Operation op)
189 if (!clicked_axisview) {
193 RouteGroup* group = NULL;
194 if (clicked_routeview) {
195 group = clicked_routeview->route()->route_group();
199 case Selection::Toggle:
200 if (selection->selected (clicked_axisview)) {
201 if (group && group->is_active()) {
202 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
203 if ((*i)->route_group() == group) {
204 selection->remove(*i);
208 selection->remove (clicked_axisview);
211 if (group && group->is_active()) {
212 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
213 if ((*i)->route_group() == group) {
218 selection->add (clicked_axisview);
224 if (group && group->is_active()) {
225 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
226 if ((*i)->route_group() == group) {
231 selection->add (clicked_axisview);
237 if (group && group->is_active()) {
238 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
239 if ((*i)->route_group() == group) {
244 selection->set (clicked_axisview);
248 case Selection::Extend:
255 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
257 begin_reversible_selection_op (X_("Set Selected Track"));
260 case Selection::Toggle:
261 if (selection->selected (&view)) {
263 selection->remove (&view);
266 selection->add (&view);
271 selection->add (&view);
275 selection->set (&view);
278 case Selection::Extend:
279 extend_selection_to_track (view);
283 commit_reversible_selection_op ();
287 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
289 if (!clicked_routeview) {
297 set_selected_track (*clicked_routeview, op, no_remove);
301 Editor::set_selected_control_point_from_click (bool press, Selection::Operation op)
303 if (!clicked_control_point) {
311 if (!selection->selected (clicked_control_point)) {
312 selection->set (clicked_control_point);
315 /* clicked on an already selected point */
319 if (selection->points.size() > 1) {
320 selection->set (clicked_control_point);
329 selection->add (clicked_control_point);
333 case Selection::Toggle:
335 /* This is a bit of a hack; if we Primary-Click-Drag a control
336 point (for push drag) we want the point we clicked on to be
337 selected, otherwise we end up confusingly dragging an
338 unselected point. So here we ensure that the point is selected
339 after the press, and if we subsequently get a release (meaning no
340 drag occurred) we set things up so that the toggle has happened.
342 if (press && !selection->selected (clicked_control_point)) {
343 /* This is the button press, and the control point is not selected; make it so,
344 in case this press leads to a drag. Also note that having done this, we don't
345 need to toggle again on release.
347 selection->toggle (clicked_control_point);
348 _control_point_toggled_on_press = true;
350 } else if (!press && !_control_point_toggled_on_press) {
351 /* This is the release, and the point wasn't toggled on the press, so do it now */
352 selection->toggle (clicked_control_point);
356 _control_point_toggled_on_press = false;
359 case Selection::Extend:
368 Editor::get_onscreen_tracks (TrackViewList& tvl)
370 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
371 if ((*i)->y_position() < _visible_canvas_height) {
377 /** Call a slot for a given `basis' track and also for any track that is in the same
378 * active route group with a particular set of properties.
380 * @param sl Slot to call.
381 * @param basis Basis track.
382 * @param prop Properties that active edit groups must share to be included in the map.
386 Editor::mapover_tracks (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
388 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
390 if (route_basis == 0) {
394 set<RouteTimeAxisView*> tracks;
395 tracks.insert (route_basis);
397 RouteGroup* group = route_basis->route()->route_group();
399 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id) ) {
401 /* the basis is a member of an active route group, with the appropriate
402 properties; find other members */
404 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
405 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
406 if (v && v->route()->route_group() == group) {
413 uint32_t const sz = tracks.size ();
415 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
420 /** Call a slot for a given `basis' track and also for any track that is in the same
421 * active route group with a particular set of properties.
423 * @param sl Slot to call.
424 * @param basis Basis track.
425 * @param prop Properties that active edit groups must share to be included in the map.
429 Editor::mapover_tracks_with_unique_playlists (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
431 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
432 set<boost::shared_ptr<Playlist> > playlists;
434 if (route_basis == 0) {
438 set<RouteTimeAxisView*> tracks;
439 tracks.insert (route_basis);
441 RouteGroup* group = route_basis->route()->route_group(); // could be null, not a problem
443 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id) ) {
445 /* the basis is a member of an active route group, with the appropriate
446 properties; find other members */
448 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
449 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
451 if (v && v->route()->route_group() == group) {
453 boost::shared_ptr<Track> t = v->track();
455 if (playlists.insert (t->playlist()).second) {
456 /* haven't seen this playlist yet */
460 /* not actually a "Track", but a timeaxis view that
461 we should mapover anyway.
470 uint32_t const sz = tracks.size ();
472 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
478 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
480 boost::shared_ptr<Playlist> pl;
481 vector<boost::shared_ptr<Region> > results;
483 boost::shared_ptr<Track> tr;
485 if ((tr = tv.track()) == 0) {
490 if (&tv == &basis->get_time_axis_view()) {
491 /* looking in same track as the original */
495 if ((pl = tr->playlist()) != 0) {
496 pl->get_equivalent_regions (basis->region(), results);
499 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
500 if ((marv = tv.view()->find_view (*ir)) != 0) {
501 all_equivs->push_back (marv);
507 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, PBD::PropertyID property) const
509 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);
511 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
513 equivalent_regions.push_back (basis);
517 Editor::get_equivalent_regions (RegionSelection & basis, PBD::PropertyID prop) const
519 RegionSelection equivalent;
521 for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
523 vector<RegionView*> eq;
525 mapover_tracks_with_unique_playlists (
526 sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
527 &(*i)->get_time_axis_view(), prop);
529 for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
540 Editor::get_regionview_count_from_region_list (boost::shared_ptr<Region> region)
542 int region_count = 0;
544 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
546 RouteTimeAxisView* tatv;
548 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
550 boost::shared_ptr<Playlist> pl;
551 vector<boost::shared_ptr<Region> > results;
553 boost::shared_ptr<Track> tr;
555 if ((tr = tatv->track()) == 0) {
560 if ((pl = (tr->playlist())) != 0) {
561 pl->get_region_list_equivalent_regions (region, results);
564 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
565 if ((marv = tatv->view()->find_view (*ir)) != 0) {
578 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op)
580 vector<RegionView*> all_equivalent_regions;
583 if (!clicked_regionview || !clicked_routeview) {
588 button_release_can_deselect = false;
591 if (op == Selection::Toggle || op == Selection::Set) {
594 case Selection::Toggle:
595 if (selection->selected (clicked_regionview)) {
598 /* whatever was clicked was selected already; do nothing here but allow
599 the button release to deselect it
602 button_release_can_deselect = true;
605 if (button_release_can_deselect) {
607 /* just remove this one region, but only on a permitted button release */
609 selection->remove (clicked_regionview);
612 /* no more deselect action on button release till a new press
613 finds an already selected object.
616 button_release_can_deselect = false;
624 if (selection->selected (clicked_routeview)) {
625 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
627 all_equivalent_regions.push_back (clicked_regionview);
630 /* add all the equivalent regions, but only on button press */
632 if (!all_equivalent_regions.empty()) {
636 selection->add (all_equivalent_regions);
642 if (!selection->selected (clicked_regionview)) {
643 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
644 selection->set (all_equivalent_regions);
647 /* clicked on an already selected region */
651 if (selection->regions.size() > 1) {
652 /* collapse region selection down to just this one region (and its equivalents) */
653 get_equivalent_regions(clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
654 selection->set(all_equivalent_regions);
666 } else if (op == Selection::Extend) {
668 list<Selectable*> results;
669 framepos_t last_frame;
670 framepos_t first_frame;
671 bool same_track = false;
673 /* 1. find the last selected regionview in the track that was clicked in */
676 first_frame = max_framepos;
678 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
679 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
681 if ((*x)->region()->last_frame() > last_frame) {
682 last_frame = (*x)->region()->last_frame();
685 if ((*x)->region()->first_frame() < first_frame) {
686 first_frame = (*x)->region()->first_frame();
695 /* 2. figure out the boundaries for our search for new objects */
697 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
698 case Evoral::OverlapNone:
699 if (last_frame < clicked_regionview->region()->first_frame()) {
700 first_frame = last_frame;
701 last_frame = clicked_regionview->region()->last_frame();
703 last_frame = first_frame;
704 first_frame = clicked_regionview->region()->first_frame();
708 case Evoral::OverlapExternal:
709 if (last_frame < clicked_regionview->region()->first_frame()) {
710 first_frame = last_frame;
711 last_frame = clicked_regionview->region()->last_frame();
713 last_frame = first_frame;
714 first_frame = clicked_regionview->region()->first_frame();
718 case Evoral::OverlapInternal:
719 if (last_frame < clicked_regionview->region()->first_frame()) {
720 first_frame = last_frame;
721 last_frame = clicked_regionview->region()->last_frame();
723 last_frame = first_frame;
724 first_frame = clicked_regionview->region()->first_frame();
728 case Evoral::OverlapStart:
729 case Evoral::OverlapEnd:
730 /* nothing to do except add clicked region to selection, since it
731 overlaps with the existing selection in this track.
738 /* click in a track that has no regions selected, so extend vertically
739 to pick out all regions that are defined by the existing selection
744 first_frame = clicked_regionview->region()->position();
745 last_frame = clicked_regionview->region()->last_frame();
747 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
748 if ((*i)->region()->position() < first_frame) {
749 first_frame = (*i)->region()->position();
751 if ((*i)->region()->last_frame() + 1 > last_frame) {
752 last_frame = (*i)->region()->last_frame();
757 /* 2. find all the tracks we should select in */
759 set<RouteTimeAxisView*> relevant_tracks;
761 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
762 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
764 relevant_tracks.insert (r);
768 set<RouteTimeAxisView*> already_in_selection;
770 if (relevant_tracks.empty()) {
772 /* no tracks selected .. thus .. if the
773 regionview we're in isn't selected
774 (i.e. we're about to extend to it), then
775 find all tracks between the this one and
779 if (!selection->selected (clicked_regionview)) {
781 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&clicked_regionview->get_time_axis_view());
785 /* add this track to the ones we will search */
787 relevant_tracks.insert (rtv);
789 /* find the track closest to this one that
790 already a selected region.
793 RouteTimeAxisView* closest = 0;
794 int distance = INT_MAX;
795 int key = rtv->route()->presentation_info().order ();
797 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
799 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
801 if (artv && artv != rtv) {
803 pair<set<RouteTimeAxisView*>::iterator,bool> result;
805 result = already_in_selection.insert (artv);
808 /* newly added to already_in_selection */
810 int d = artv->route()->presentation_info().order ();
814 if (abs (d) < distance) {
824 /* now add all tracks between that one and this one */
826 int okey = closest->route()->presentation_info().order ();
832 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
833 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
834 if (artv && artv != rtv) {
836 int k = artv->route()->presentation_info().order ();
838 if (k >= okey && k <= key) {
840 /* in range but don't add it if
841 it already has tracks selected.
842 this avoids odd selection
843 behaviour that feels wrong.
846 if (find (already_in_selection.begin(),
847 already_in_selection.end(),
848 artv) == already_in_selection.end()) {
850 relevant_tracks.insert (artv);
860 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
861 one that was clicked.
864 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
865 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
868 /* 4. convert to a vector of regions */
870 vector<RegionView*> regions;
872 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
875 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
876 regions.push_back (arv);
880 if (!regions.empty()) {
881 selection->add (regions);
883 } else if (selection->regions.empty() && !selection->selected (clicked_regionview)) {
884 /* ensure that at least the clicked regionview is selected. */
885 selection->set (clicked_regionview);
896 Editor::set_selection (std::list<Selectable*> s, Selection::Operation op)
901 begin_reversible_selection_op (X_("set selection"));
903 case Selection::Toggle:
904 selection->toggle (s);
909 case Selection::Extend:
917 commit_reversible_selection_op () ;
921 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
923 vector<RegionView*> all_equivalent_regions;
925 get_regions_corresponding_to (region, all_equivalent_regions, region->whole_file());
927 if (all_equivalent_regions.empty()) {
931 begin_reversible_selection_op (X_("set selected regions"));
934 case Selection::Toggle:
935 /* XXX this is not correct */
936 selection->toggle (all_equivalent_regions);
939 selection->set (all_equivalent_regions);
941 case Selection::Extend:
942 selection->add (all_equivalent_regions);
945 selection->add (all_equivalent_regions);
949 commit_reversible_selection_op () ;
953 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
956 boost::shared_ptr<Region> r (weak_r.lock());
962 if ((rv = sv->find_view (r)) == 0) {
966 /* don't reset the selection if its something other than
967 a single other region.
970 if (selection->regions.size() > 1) {
974 begin_reversible_selection_op (X_("set selected regions"));
978 commit_reversible_selection_op () ;
983 struct SelectionOrderSorter {
984 bool operator() (TimeAxisView const * const a, TimeAxisView const * const b) const {
985 boost::shared_ptr<Stripable> sa = a->stripable ();
986 boost::shared_ptr<Stripable> sb = b->stripable ();
996 return sa->presentation_info().selection_cnt() < sb->presentation_info().selection_cnt();
1001 Editor::presentation_info_changed (PropertyChange const & what_changed)
1003 /* We cannot ensure ordering of the handlers for
1004 * PresentationInfo::Changed, so we have to do everything in order
1005 * here, as a single handler.
1008 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1009 (*i)->set_selected (false);
1010 (*i)->hide_selection ();
1013 /* STEP 1: set the GUI selection state (in which TimeAxisViews for the
1014 * currently selected stripable/controllable duples are found and added
1017 selection->core_selection_changed (what_changed);
1019 /* STEP 2: update TimeAxisView's knowledge of their selected state
1024 pc.add (Properties::selected);
1026 if (what_changed.contains (Properties::selected)) {
1028 StripableNotificationListPtr stripables (new StripableNotificationList);
1030 switch (selection->tracks.size()) {
1034 set_selected_mixer_strip (*(selection->tracks.back()));
1035 if (!_track_selection_change_without_scroll) {
1036 ensure_time_axis_view_is_visible (*(selection->tracks.back()), false);
1041 CoreSelection::StripableAutomationControls sc;
1042 _session->selection().get_stripables (sc);
1044 for (CoreSelection::StripableAutomationControls::const_iterator i = sc.begin(); i != sc.end(); ++i) {
1046 AxisView* av = axis_view_by_stripable ((*i).stripable);
1052 TimeAxisView* tav = dynamic_cast<TimeAxisView*> (av);
1055 continue; /* impossible */
1058 if (!(*i).controllable) {
1060 /* "parent" track selected */
1061 tav->set_selected (true);
1062 tav->reshow_selection (selection->time);
1066 /* possibly a child */
1068 TimeAxisView::Children c = tav->get_child_list ();
1070 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
1072 boost::shared_ptr<AutomationControl> control = (*j)->control ();
1074 if (control != (*i).controllable) {
1078 (*j)->set_selected (true);
1079 (*j)->reshow_selection (selection->time);
1083 stripables->push_back ((*i).stripable);
1086 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
1088 sensitize_the_right_region_actions (false);
1090 /* STEP 4: notify control protocols */
1092 ControlProtocolManager::instance().stripable_selection_changed (stripables);
1094 if (sfbrowser && _session && !_session->deletion_in_progress()) {
1095 uint32_t audio_track_cnt = 0;
1096 uint32_t midi_track_cnt = 0;
1098 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
1099 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*x);
1102 if (atv->is_audio_track()) {
1107 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(*x);
1110 if (mtv->is_midi_track()) {
1117 sfbrowser->reset (audio_track_cnt, midi_track_cnt);
1121 /* STEP 4: update EditorRoutes treeview */
1125 soh.add (Properties::selected);
1126 soh.add (Properties::order);
1127 soh.add (Properties::hidden);
1129 if (what_changed.contains (soh)) {
1130 _routes->sync_treeview_from_presentation_info (what_changed);
1135 Editor::time_selection_changed ()
1137 /* XXX this is superficially inefficient. Hide the selection in all
1138 * tracks, then show it in all selected tracks.
1140 * However, if you investigate what this actually does, it isn't
1141 * anywhere nearly as bad as it may appear. Remember: nothing is
1142 * redrawn or even recomputed during these two loops - that only
1143 * happens when we next render ...
1146 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1147 (*i)->hide_selection ();
1150 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1151 (*i)->show_selection (selection->time);
1154 if (selection->time.empty()) {
1155 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
1157 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
1160 /* propagate into backend, but only when there is no drag or we are at
1161 * the end of a drag, otherwise this is too expensive (could case a
1162 * locate per mouse motion event.
1165 if (_session && !_drags->active()) {
1166 if (selection->time.length() != 0) {
1167 _session->set_range_selection (selection->time.start(), selection->time.end_frame());
1169 _session->clear_range_selection ();
1174 /** Set all region actions to have a given sensitivity */
1176 Editor::sensitize_all_region_actions (bool s)
1178 Glib::ListHandle<Glib::RefPtr<Action> > all = _region_actions->get_actions ();
1180 for (Glib::ListHandle<Glib::RefPtr<Action> >::iterator i = all.begin(); i != all.end(); ++i) {
1181 (*i)->set_sensitive (s);
1184 _all_region_actions_sensitized = s;
1187 /** Sensitize region-based actions.
1189 * This method is called from whenever we leave the canvas, either by moving
1190 * the pointer out of it, or by popping up a context menu. See
1191 * Editor::{entered,left}_track_canvas() for details there.
1194 Editor::sensitize_the_right_region_actions (bool because_canvas_crossing)
1196 bool have_selection = false;
1197 bool have_entered = false;
1198 bool have_edit_point = false;
1201 // std::cerr << "STRRA: crossing ? " << because_canvas_crossing << " within ? " << within_track_canvas
1204 if (!selection->regions.empty()) {
1205 have_selection = true;
1206 rs = selection->regions;
1209 if (entered_regionview) {
1210 have_entered = true;
1211 rs.add (entered_regionview);
1214 if (rs.empty() && !selection->tracks.empty()) {
1216 /* no selected regions, but some selected tracks.
1219 if (_edit_point == EditAtMouse) {
1220 if (!within_track_canvas) {
1221 /* pointer is not in canvas, so edit point is meaningless */
1222 have_edit_point = false;
1224 /* inside canvas. we don't know where the edit
1225 point will be when an action is invoked, but
1226 assume it could intersect with a region.
1228 have_edit_point = true;
1231 RegionSelection at_edit_point;
1232 framepos_t const where = get_preferred_edit_position (Editing::EDIT_IGNORE_NONE, false, !within_track_canvas);
1233 get_regions_at (at_edit_point, where, selection->tracks);
1234 if (!at_edit_point.empty()) {
1235 have_edit_point = true;
1238 rs.insert (rs.end(), at_edit_point.begin(), at_edit_point.end());
1243 //std::cerr << "\tfinal have selection: " << have_selection
1244 // << " have entered " << have_entered
1245 // << " have edit point " << have_edit_point
1246 // << " EP = " << enum_2_string (_edit_point)
1249 typedef std::map<std::string,RegionAction> RegionActionMap;
1251 _ignore_region_action = true;
1253 for (RegionActionMap::iterator x = region_action_map.begin(); x != region_action_map.end(); ++x) {
1254 RegionActionTarget tgt = x->second.target;
1255 bool sensitive = false;
1257 if ((tgt & SelectedRegions) && have_selection) {
1259 } else if ((tgt & EnteredRegions) && have_entered) {
1261 } else if ((tgt & EditPointRegions) && have_edit_point) {
1265 x->second.action->set_sensitive (sensitive);
1268 /* Look through the regions that are selected and make notes about what we have got */
1270 bool have_audio = false;
1271 bool have_multichannel_audio = false;
1272 bool have_midi = false;
1273 bool have_locked = false;
1274 bool have_unlocked = false;
1275 bool have_video_locked = false;
1276 bool have_video_unlocked = false;
1277 bool have_position_lock_style_audio = false;
1278 bool have_position_lock_style_music = false;
1279 bool have_muted = false;
1280 bool have_unmuted = false;
1281 bool have_opaque = false;
1282 bool have_non_opaque = false;
1283 bool have_not_at_natural_position = false;
1284 bool have_envelope_active = false;
1285 bool have_envelope_inactive = false;
1286 bool have_non_unity_scale_amplitude = false;
1287 bool have_compound_regions = false;
1288 bool have_inactive_fade_in = false;
1289 bool have_inactive_fade_out = false;
1290 bool have_active_fade_in = false;
1291 bool have_active_fade_out = false;
1292 bool have_transients = false;
1294 for (list<RegionView*>::const_iterator i = rs.begin(); i != rs.end(); ++i) {
1296 boost::shared_ptr<Region> r = (*i)->region ();
1297 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
1301 if (ar->n_channels() > 1) {
1302 have_multichannel_audio = true;
1306 if (boost::dynamic_pointer_cast<MidiRegion> (r)) {
1310 if (r->is_compound()) {
1311 have_compound_regions = true;
1317 have_unlocked = true;
1320 if (r->video_locked()) {
1321 have_video_locked = true;
1323 have_video_unlocked = true;
1326 if (r->position_lock_style() == MusicTime) {
1327 have_position_lock_style_music = true;
1329 have_position_lock_style_audio = true;
1335 have_unmuted = true;
1341 have_non_opaque = true;
1344 if (!r->at_natural_position()) {
1345 have_not_at_natural_position = true;
1348 if (r->has_transients ()){
1349 have_transients = true;
1353 if (ar->envelope_active()) {
1354 have_envelope_active = true;
1356 have_envelope_inactive = true;
1359 if (ar->scale_amplitude() != 1) {
1360 have_non_unity_scale_amplitude = true;
1363 if (ar->fade_in_active ()) {
1364 have_active_fade_in = true;
1366 have_inactive_fade_in = true;
1369 if (ar->fade_out_active ()) {
1370 have_active_fade_out = true;
1372 have_inactive_fade_out = true;
1377 _region_actions->get_action("split-region-at-transients")->set_sensitive (have_transients);
1379 if (rs.size() > 1) {
1380 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1381 _region_actions->get_action("show-region-properties")->set_sensitive (false);
1382 _region_actions->get_action("rename-region")->set_sensitive (false);
1384 /* XXX need to check whether there is than 1 per
1385 playlist, because otherwise this makes no sense.
1387 _region_actions->get_action("combine-regions")->set_sensitive (true);
1389 _region_actions->get_action("combine-regions")->set_sensitive (false);
1391 } else if (rs.size() == 1) {
1392 _region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
1393 _region_actions->get_action("close-region-gaps")->set_sensitive (false);
1394 _region_actions->get_action("combine-regions")->set_sensitive (false);
1397 if (!have_multichannel_audio) {
1398 _region_actions->get_action("split-multichannel-region")->set_sensitive (false);
1402 editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (false);
1403 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1404 _region_actions->get_action("quantize-region")->set_sensitive (false);
1405 _region_actions->get_action("legatize-region")->set_sensitive (false);
1406 _region_actions->get_action("remove-overlap")->set_sensitive (false);
1407 _region_actions->get_action("transform-region")->set_sensitive (false);
1408 _region_actions->get_action("fork-region")->set_sensitive (false);
1409 _region_actions->get_action("insert-patch-change-context")->set_sensitive (false);
1410 _region_actions->get_action("insert-patch-change")->set_sensitive (false);
1411 _region_actions->get_action("transpose-region")->set_sensitive (false);
1413 editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (true);
1414 /* others were already marked sensitive */
1417 /* ok, moving along... */
1419 if (have_compound_regions) {
1420 _region_actions->get_action("uncombine-regions")->set_sensitive (true);
1422 _region_actions->get_action("uncombine-regions")->set_sensitive (false);
1427 if (have_envelope_active && !have_envelope_inactive) {
1428 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active ();
1429 } else if (have_envelope_active && have_envelope_inactive) {
1430 // Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_inconsistent ();
1435 _region_actions->get_action("loudness-analyze-region")->set_sensitive (false);
1436 _region_actions->get_action("spectral-analyze-region")->set_sensitive (false);
1437 _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
1438 _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
1439 _region_actions->get_action("pitch-shift-region")->set_sensitive (false);
1440 _region_actions->get_action("strip-region-silence")->set_sensitive (false);
1441 _region_actions->get_action("show-rhythm-ferret")->set_sensitive (false);
1445 if (!have_non_unity_scale_amplitude || !have_audio) {
1446 _region_actions->get_action("reset-region-scale-amplitude")->set_sensitive (false);
1449 Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"));
1450 a->set_active (have_locked && !have_unlocked);
1451 if (have_locked && have_unlocked) {
1452 // a->set_inconsistent ();
1455 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-video-lock"));
1456 a->set_active (have_video_locked && !have_video_unlocked);
1457 if (have_video_locked && have_video_unlocked) {
1458 // a->set_inconsistent ();
1461 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
1462 a->set_active (have_position_lock_style_music && !have_position_lock_style_audio);
1464 vector<Widget*> proxies = a->get_proxies();
1465 for (vector<Widget*>::iterator p = proxies.begin(); p != proxies.end(); ++p) {
1466 Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (*p);
1468 cmi->set_inconsistent (have_position_lock_style_music && have_position_lock_style_audio);
1472 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"));
1473 a->set_active (have_muted && !have_unmuted);
1474 if (have_muted && have_unmuted) {
1475 // a->set_inconsistent ();
1478 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"));
1479 a->set_active (have_opaque && !have_non_opaque);
1480 if (have_opaque && have_non_opaque) {
1481 // a->set_inconsistent ();
1484 if (!have_not_at_natural_position) {
1485 _region_actions->get_action("naturalize-region")->set_sensitive (false);
1488 /* XXX: should also check that there is a track of the appropriate type for the selected region */
1489 if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
1490 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (false);
1492 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (true);
1495 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-in"));
1496 a->set_active (have_active_fade_in && !have_inactive_fade_in);
1497 if (have_active_fade_in && have_inactive_fade_in) {
1498 // a->set_inconsistent ();
1501 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-out"));
1502 a->set_active (have_active_fade_out && !have_inactive_fade_out);
1504 if (have_active_fade_out && have_inactive_fade_out) {
1505 // a->set_inconsistent ();
1508 bool const have_active_fade = have_active_fade_in || have_active_fade_out;
1509 bool const have_inactive_fade = have_inactive_fade_in || have_inactive_fade_out;
1511 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fades"));
1512 a->set_active (have_active_fade && !have_inactive_fade);
1514 if (have_active_fade && have_inactive_fade) {
1515 // a->set_inconsistent ();
1518 _ignore_region_action = false;
1520 _all_region_actions_sensitized = false;
1524 Editor::region_selection_changed ()
1526 _regions->block_change_connection (true);
1527 editor_regions_selection_changed_connection.block(true);
1529 if (_region_selection_change_updates_region_list) {
1530 _regions->unselect_all ();
1533 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1534 (*i)->set_selected_regionviews (selection->regions);
1537 if (_region_selection_change_updates_region_list) {
1538 _regions->set_selected (selection->regions);
1541 _regions->block_change_connection (false);
1542 editor_regions_selection_changed_connection.block(false);
1544 sensitize_the_right_region_actions (false);
1546 /* propagate into backend */
1549 if (!selection->regions.empty()) {
1550 _session->set_object_selection (selection->regions.start(), selection->regions.end_frame());
1552 _session->clear_object_selection ();
1559 Editor::point_selection_changed ()
1561 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1562 (*i)->set_selected_points (selection->points);
1567 Editor::select_all_in_track (Selection::Operation op)
1569 list<Selectable *> touched;
1571 if (!clicked_routeview) {
1575 begin_reversible_selection_op (X_("Select All in Track"));
1577 clicked_routeview->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1580 case Selection::Toggle:
1581 selection->add (touched);
1583 case Selection::Set:
1584 selection->set (touched);
1586 case Selection::Extend:
1587 /* meaningless, because we're selecting everything */
1589 case Selection::Add:
1590 selection->add (touched);
1594 commit_reversible_selection_op ();
1598 Editor::select_all_internal_edit (Selection::Operation)
1600 bool selected = false;
1602 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1603 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1605 mrv->select_all_notes ();
1610 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(entered_regionview);
1612 mrv->select_all_notes ();
1620 Editor::select_all_objects (Selection::Operation op)
1622 list<Selectable *> touched;
1624 if (internal_editing() && select_all_internal_edit(op)) {
1625 return; // Selected notes
1630 if (selection->tracks.empty()) {
1633 ts = selection->tracks;
1636 for (TrackViewList::iterator iter = ts.begin(); iter != ts.end(); ++iter) {
1637 if ((*iter)->hidden()) {
1640 (*iter)->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1643 begin_reversible_selection_op (X_("select all"));
1645 case Selection::Add:
1646 selection->add (touched);
1648 case Selection::Toggle:
1649 selection->toggle (touched);
1651 case Selection::Set:
1652 selection->set (touched);
1654 case Selection::Extend:
1655 /* meaningless, because we're selecting everything */
1658 commit_reversible_selection_op ();
1662 Editor::invert_selection_in_track ()
1664 list<Selectable *> touched;
1666 if (!clicked_routeview) {
1670 begin_reversible_selection_op (X_("Invert Selection in Track"));
1671 clicked_routeview->get_inverted_selectables (*selection, touched);
1672 selection->set (touched);
1673 commit_reversible_selection_op ();
1677 Editor::invert_selection ()
1679 list<Selectable *> touched;
1681 if (internal_editing()) {
1682 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1683 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1685 mrv->invert_selection ();
1691 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1692 if ((*iter)->hidden()) {
1695 (*iter)->get_inverted_selectables (*selection, touched);
1698 begin_reversible_selection_op (X_("Invert Selection"));
1699 selection->set (touched);
1700 commit_reversible_selection_op ();
1703 /** @param start Start time in session frames.
1704 * @param end End time in session frames.
1705 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
1706 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
1707 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
1708 * within the region are already selected.
1711 Editor::select_all_within (framepos_t start, framepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected)
1713 list<Selectable*> found;
1715 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1717 if ((*iter)->hidden()) {
1721 (*iter)->get_selectables (start, end, top, bot, found);
1724 if (found.empty()) {
1725 selection->clear_objects();
1726 selection->clear_time ();
1730 if (preserve_if_selected && op != Selection::Toggle) {
1731 list<Selectable*>::iterator i = found.begin();
1732 while (i != found.end() && (*i)->selected()) {
1736 if (i == found.end()) {
1741 begin_reversible_selection_op (X_("select all within"));
1743 case Selection::Add:
1744 selection->add (found);
1746 case Selection::Toggle:
1747 selection->toggle (found);
1749 case Selection::Set:
1750 selection->set (found);
1752 case Selection::Extend:
1753 /* not defined yet */
1757 commit_reversible_selection_op ();
1761 Editor::set_selection_from_region ()
1763 if (selection->regions.empty()) {
1767 /* find all the tracks that have selected regions */
1769 set<TimeAxisView*> tracks;
1771 for (RegionSelection::const_iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
1772 tracks.insert (&(*r)->get_time_axis_view());
1776 tvl.insert (tvl.end(), tracks.begin(), tracks.end());
1778 /* select range (this will clear the region selection) */
1780 selection->set (selection->regions.start(), selection->regions.end_frame());
1782 /* and select the tracks */
1784 selection->set (tvl);
1786 if (!get_smart_mode () || !mouse_mode == Editing::MouseObject) {
1787 set_mouse_mode (Editing::MouseRange, false);
1792 Editor::set_selection_from_punch()
1796 if ((location = _session->locations()->auto_punch_location()) == 0) {
1800 set_selection_from_range (*location);
1804 Editor::set_selection_from_loop()
1808 if ((location = _session->locations()->auto_loop_location()) == 0) {
1811 set_selection_from_range (*location);
1815 Editor::set_selection_from_range (Location& loc)
1817 begin_reversible_selection_op (X_("set selection from range"));
1818 selection->set (loc.start(), loc.end());
1819 commit_reversible_selection_op ();
1821 if (!get_smart_mode () || mouse_mode != Editing::MouseObject) {
1822 set_mouse_mode (MouseRange, false);
1827 Editor::select_all_selectables_using_time_selection ()
1829 list<Selectable *> touched;
1831 if (selection->time.empty()) {
1835 framepos_t start = selection->time[clicked_selection].start;
1836 framepos_t end = selection->time[clicked_selection].end;
1838 if (end - start < 1) {
1844 if (selection->tracks.empty()) {
1847 ts = &selection->tracks;
1850 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1851 if ((*iter)->hidden()) {
1854 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1857 begin_reversible_selection_op (X_("select all from range"));
1858 selection->set (touched);
1859 commit_reversible_selection_op ();
1864 Editor::select_all_selectables_using_punch()
1866 Location* location = _session->locations()->auto_punch_location();
1867 list<Selectable *> touched;
1869 if (location == 0 || (location->end() - location->start() <= 1)) {
1876 if (selection->tracks.empty()) {
1879 ts = &selection->tracks;
1882 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1883 if ((*iter)->hidden()) {
1886 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1888 begin_reversible_selection_op (X_("select all from punch"));
1889 selection->set (touched);
1890 commit_reversible_selection_op ();
1895 Editor::select_all_selectables_using_loop()
1897 Location* location = _session->locations()->auto_loop_location();
1898 list<Selectable *> touched;
1900 if (location == 0 || (location->end() - location->start() <= 1)) {
1907 if (selection->tracks.empty()) {
1910 ts = &selection->tracks;
1913 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1914 if ((*iter)->hidden()) {
1917 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1919 begin_reversible_selection_op (X_("select all from loop"));
1920 selection->set (touched);
1921 commit_reversible_selection_op ();
1926 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1930 list<Selectable *> touched;
1933 start = cursor->current_frame();
1934 end = _session->current_end_frame();
1936 if (cursor->current_frame() > 0) {
1938 end = cursor->current_frame() - 1;
1944 if (internal_editing()) {
1945 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1946 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1948 mrv->select_range (start, end);
1955 begin_reversible_selection_op (X_("select all after cursor"));
1957 begin_reversible_selection_op (X_("select all before cursor"));
1962 if (selection->tracks.empty()) {
1965 ts = &selection->tracks;
1968 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1969 if ((*iter)->hidden()) {
1972 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1974 selection->set (touched);
1975 commit_reversible_selection_op ();
1979 Editor::select_all_selectables_using_edit (bool after, bool from_context_menu)
1983 list<Selectable *> touched;
1986 start = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu);
1987 end = _session->current_end_frame();
1989 if ((end = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu)) > 1) {
1997 if (internal_editing()) {
1998 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1999 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
2000 mrv->select_range (start, end);
2006 begin_reversible_selection_op (X_("select all after edit"));
2008 begin_reversible_selection_op (X_("select all before edit"));
2013 if (selection->tracks.empty()) {
2016 ts = &selection->tracks;
2019 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
2020 if ((*iter)->hidden()) {
2023 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
2025 selection->set (touched);
2026 commit_reversible_selection_op ();
2030 Editor::select_all_selectables_between (bool within)
2034 list<Selectable *> touched;
2036 if (!get_edit_op_range (start, end)) {
2040 if (internal_editing()) {
2041 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2042 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
2043 mrv->select_range (start, end);
2050 if (selection->tracks.empty()) {
2053 ts = &selection->tracks;
2056 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
2057 if ((*iter)->hidden()) {
2060 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched, within);
2063 begin_reversible_selection_op (X_("Select all Selectables Between"));
2064 selection->set (touched);
2065 commit_reversible_selection_op ();
2069 Editor::select_range_between ()
2074 if ( !selection->time.empty() ) {
2075 selection->clear_time ();
2078 if (!get_edit_op_range (start, end)) {
2082 if (!get_smart_mode () || mouse_mode != Editing::MouseObject) {
2083 set_mouse_mode (MouseRange, false);
2086 begin_reversible_selection_op (X_("Select Range Between"));
2087 selection->set (start, end);
2088 commit_reversible_selection_op ();
2092 Editor::get_edit_op_range (framepos_t& start, framepos_t& end) const
2097 /* if an explicit range exists, use it */
2099 if ( (mouse_mode == MouseRange || get_smart_mode() ) && !selection->time.empty()) {
2100 /* we know that these are ordered */
2101 start = selection->time.start();
2102 end = selection->time.end_frame();
2110 // if (!mouse_frame (m, ignored)) {
2111 // /* mouse is not in a canvas, try playhead+selected marker.
2112 // this is probably most true when using menus.
2115 // if (selection->markers.empty()) {
2119 // start = selection->markers.front()->position();
2120 // end = _session->audible_frame();
2124 // switch (_edit_point) {
2125 // case EditAtPlayhead:
2126 // if (selection->markers.empty()) {
2127 // /* use mouse + playhead */
2129 // end = _session->audible_frame();
2131 // /* use playhead + selected marker */
2132 // start = _session->audible_frame();
2133 // end = selection->markers.front()->position();
2137 // case EditAtMouse:
2138 // /* use mouse + selected marker */
2139 // if (selection->markers.empty()) {
2141 // end = _session->audible_frame();
2143 // start = selection->markers.front()->position();
2148 // case EditAtSelectedMarker:
2149 // /* use mouse + selected marker */
2150 // if (selection->markers.empty()) {
2152 // MessageDialog win (_("No edit range defined"),
2157 // win.set_secondary_text (
2158 // _("the edit point is Selected Marker\nbut there is no selected marker."));
2161 // win.set_default_response (RESPONSE_CLOSE);
2162 // win.set_position (Gtk::WIN_POS_MOUSE);
2167 // return false; // NO RANGE
2169 // start = selection->markers.front()->position();
2175 // if (start == end) {
2179 // if (start > end) {
2180 // swap (start, end);
2183 /* turn range into one delimited by start...end,
2193 Editor::deselect_all ()
2195 begin_reversible_selection_op (X_("Deselect All"));
2196 selection->clear ();
2197 commit_reversible_selection_op ();
2201 Editor::select_range (framepos_t s, framepos_t e)
2203 begin_reversible_selection_op (X_("Select Range"));
2204 selection->add (clicked_axisview);
2205 selection->time.clear ();
2206 long ret = selection->set (s, e);
2207 commit_reversible_selection_op ();