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/midi_region.h"
27 #include "ardour/playlist.h"
28 #include "ardour/profile.h"
29 #include "ardour/route_group.h"
30 #include "ardour/session.h"
32 #include "control_protocol/control_protocol.h"
34 #include "editor_drag.h"
37 #include "audio_time_axis.h"
38 #include "audio_region_view.h"
39 #include "audio_streamview.h"
40 #include "automation_line.h"
41 #include "control_point.h"
42 #include "editor_regions.h"
43 #include "editor_cursors.h"
44 #include "midi_region_view.h"
50 using namespace ARDOUR;
54 using namespace Gtkmm2ext;
55 using namespace Editing;
57 struct TrackViewByPositionSorter
59 bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
60 return a->y_position() < b->y_position();
65 Editor::extend_selection_to_track (TimeAxisView& view)
67 if (selection->selected (&view)) {
68 /* already selected, do nothing */
72 if (selection->tracks.empty()) {
74 if (!selection->selected (&view)) {
75 selection->set (&view);
82 /* something is already selected, so figure out which range of things to add */
84 TrackViewList to_be_added;
85 TrackViewList sorted = track_views;
86 TrackViewByPositionSorter cmp;
87 bool passed_clicked = false;
92 /* figure out if we should go forward or backwards */
94 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
97 passed_clicked = true;
100 if (selection->selected (*i)) {
101 if (passed_clicked) {
110 passed_clicked = false;
114 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
117 passed_clicked = true;
121 if (passed_clicked) {
122 if ((*i)->hidden()) {
125 if (selection->selected (*i)) {
127 } else if (!(*i)->hidden()) {
128 to_be_added.push_back (*i);
135 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
138 passed_clicked = true;
142 if (passed_clicked) {
144 if ((*r)->hidden()) {
148 if (selection->selected (*r)) {
150 } else if (!(*r)->hidden()) {
151 to_be_added.push_back (*r);
157 if (!selection->selected (&view)) {
158 to_be_added.push_back (&view);
161 if (!to_be_added.empty()) {
162 selection->add (to_be_added);
170 Editor::select_all_tracks ()
172 TrackViewList visible_views;
173 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
174 if ((*i)->marked_for_display()) {
175 visible_views.push_back (*i);
178 PBD::Unwinder<bool> uw (_track_selection_change_without_scroll, true);
179 selection->set (visible_views);
182 /** Select clicked_axisview, unless there are no currently selected
183 * tracks, in which case nothing will happen unless `force' is true.
186 Editor::set_selected_track_as_side_effect (Selection::Operation op)
188 if (!clicked_axisview) {
192 RouteGroup* group = NULL;
193 if (clicked_routeview) {
194 group = clicked_routeview->route()->route_group();
198 case Selection::Toggle:
199 if (selection->selected (clicked_axisview)) {
200 if (group && group->is_active()) {
201 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
202 if ((*i)->route_group() == group) {
203 selection->remove(*i);
207 selection->remove (clicked_axisview);
210 if (group && group->is_active()) {
211 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
212 if ((*i)->route_group() == group) {
217 selection->add (clicked_axisview);
223 if (group && group->is_active()) {
224 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
225 if ((*i)->route_group() == group) {
230 selection->add (clicked_axisview);
236 if (group && group->is_active()) {
237 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
238 if ((*i)->route_group() == group) {
243 selection->set (clicked_axisview);
247 case Selection::Extend:
254 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
256 begin_reversible_selection_op (X_("Set Selected Track"));
259 case Selection::Toggle:
260 if (selection->selected (&view)) {
262 selection->remove (&view);
265 selection->add (&view);
270 if (!selection->selected (&view)) {
271 selection->add (&view);
276 selection->set (&view);
279 case Selection::Extend:
280 extend_selection_to_track (view);
284 commit_reversible_selection_op ();
288 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
290 if (!clicked_routeview) {
298 set_selected_track (*clicked_routeview, op, no_remove);
302 Editor::set_selected_control_point_from_click (bool press, Selection::Operation op)
304 if (!clicked_control_point) {
312 if (!selection->selected (clicked_control_point)) {
313 selection->set (clicked_control_point);
316 /* clicked on an already selected point */
320 if (selection->points.size() > 1) {
321 selection->set (clicked_control_point);
330 selection->add (clicked_control_point);
334 case Selection::Toggle:
336 /* This is a bit of a hack; if we Primary-Click-Drag a control
337 point (for push drag) we want the point we clicked on to be
338 selected, otherwise we end up confusingly dragging an
339 unselected point. So here we ensure that the point is selected
340 after the press, and if we subsequently get a release (meaning no
341 drag occurred) we set things up so that the toggle has happened.
343 if (press && !selection->selected (clicked_control_point)) {
344 /* This is the button press, and the control point is not selected; make it so,
345 in case this press leads to a drag. Also note that having done this, we don't
346 need to toggle again on release.
348 selection->toggle (clicked_control_point);
349 _control_point_toggled_on_press = true;
351 } else if (!press && !_control_point_toggled_on_press) {
352 /* This is the release, and the point wasn't toggled on the press, so do it now */
353 selection->toggle (clicked_control_point);
357 _control_point_toggled_on_press = false;
360 case Selection::Extend:
369 Editor::get_onscreen_tracks (TrackViewList& tvl)
371 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
372 if ((*i)->y_position() < _visible_canvas_height) {
378 /** Call a slot for a given `basis' track and also for any track that is in the same
379 * active route group with a particular set of properties.
381 * @param sl Slot to call.
382 * @param basis Basis track.
383 * @param prop Properties that active edit groups must share to be included in the map.
387 Editor::mapover_tracks (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
389 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
391 if (route_basis == 0) {
395 set<RouteTimeAxisView*> tracks;
396 tracks.insert (route_basis);
398 RouteGroup* group = route_basis->route()->route_group();
400 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id) ) {
402 /* the basis is a member of an active route group, with the appropriate
403 properties; find other members */
405 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
406 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
407 if (v && v->route()->route_group() == group) {
414 uint32_t const sz = tracks.size ();
416 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
421 /** Call a slot for a given `basis' track and also for any track that is in the same
422 * active route group with a particular set of properties.
424 * @param sl Slot to call.
425 * @param basis Basis track.
426 * @param prop Properties that active edit groups must share to be included in the map.
430 Editor::mapover_tracks_with_unique_playlists (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
432 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
433 set<boost::shared_ptr<Playlist> > playlists;
435 if (route_basis == 0) {
439 set<RouteTimeAxisView*> tracks;
440 tracks.insert (route_basis);
442 RouteGroup* group = route_basis->route()->route_group(); // could be null, not a problem
444 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id) ) {
446 /* the basis is a member of an active route group, with the appropriate
447 properties; find other members */
449 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
450 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
452 if (v && v->route()->route_group() == group) {
454 boost::shared_ptr<Track> t = v->track();
456 if (playlists.insert (t->playlist()).second) {
457 /* haven't seen this playlist yet */
461 /* not actually a "Track", but a timeaxis view that
462 we should mapover anyway.
471 uint32_t const sz = tracks.size ();
473 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
479 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
481 boost::shared_ptr<Playlist> pl;
482 vector<boost::shared_ptr<Region> > results;
484 boost::shared_ptr<Track> tr;
486 if ((tr = tv.track()) == 0) {
491 if (&tv == &basis->get_time_axis_view()) {
492 /* looking in same track as the original */
496 if ((pl = tr->playlist()) != 0) {
497 pl->get_equivalent_regions (basis->region(), results);
500 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
501 if ((marv = tv.view()->find_view (*ir)) != 0) {
502 all_equivs->push_back (marv);
508 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, PBD::PropertyID property) const
510 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);
512 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
514 equivalent_regions.push_back (basis);
518 Editor::get_equivalent_regions (RegionSelection & basis, PBD::PropertyID prop) const
520 RegionSelection equivalent;
522 for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
524 vector<RegionView*> eq;
526 mapover_tracks_with_unique_playlists (
527 sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
528 &(*i)->get_time_axis_view(), prop);
530 for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
541 Editor::get_regionview_count_from_region_list (boost::shared_ptr<Region> region)
543 int region_count = 0;
545 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
547 RouteTimeAxisView* tatv;
549 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
551 boost::shared_ptr<Playlist> pl;
552 vector<boost::shared_ptr<Region> > results;
554 boost::shared_ptr<Track> tr;
556 if ((tr = tatv->track()) == 0) {
561 if ((pl = (tr->playlist())) != 0) {
562 pl->get_region_list_equivalent_regions (region, results);
565 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
566 if ((marv = tatv->view()->find_view (*ir)) != 0) {
579 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op)
581 vector<RegionView*> all_equivalent_regions;
584 if (!clicked_regionview || !clicked_routeview) {
589 button_release_can_deselect = false;
592 if (op == Selection::Toggle || op == Selection::Set) {
595 case Selection::Toggle:
596 if (selection->selected (clicked_regionview)) {
599 /* whatever was clicked was selected already; do nothing here but allow
600 the button release to deselect it
603 button_release_can_deselect = true;
606 if (button_release_can_deselect) {
608 /* just remove this one region, but only on a permitted button release */
610 selection->remove (clicked_regionview);
613 /* no more deselect action on button release till a new press
614 finds an already selected object.
617 button_release_can_deselect = false;
625 if (selection->selected (clicked_routeview)) {
626 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
628 all_equivalent_regions.push_back (clicked_regionview);
631 /* add all the equivalent regions, but only on button press */
633 if (!all_equivalent_regions.empty()) {
637 selection->add (all_equivalent_regions);
643 if (!selection->selected (clicked_regionview)) {
644 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
645 selection->set (all_equivalent_regions);
648 /* clicked on an already selected region */
652 if (selection->regions.size() > 1) {
653 /* collapse region selection down to just this one region (and its equivalents) */
654 get_equivalent_regions(clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
655 selection->set(all_equivalent_regions);
667 } else if (op == Selection::Extend) {
669 list<Selectable*> results;
670 framepos_t last_frame;
671 framepos_t first_frame;
672 bool same_track = false;
674 /* 1. find the last selected regionview in the track that was clicked in */
677 first_frame = max_framepos;
679 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
680 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
682 if ((*x)->region()->last_frame() > last_frame) {
683 last_frame = (*x)->region()->last_frame();
686 if ((*x)->region()->first_frame() < first_frame) {
687 first_frame = (*x)->region()->first_frame();
696 /* 2. figure out the boundaries for our search for new objects */
698 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
699 case Evoral::OverlapNone:
700 if (last_frame < clicked_regionview->region()->first_frame()) {
701 first_frame = last_frame;
702 last_frame = clicked_regionview->region()->last_frame();
704 last_frame = first_frame;
705 first_frame = clicked_regionview->region()->first_frame();
709 case Evoral::OverlapExternal:
710 if (last_frame < clicked_regionview->region()->first_frame()) {
711 first_frame = last_frame;
712 last_frame = clicked_regionview->region()->last_frame();
714 last_frame = first_frame;
715 first_frame = clicked_regionview->region()->first_frame();
719 case Evoral::OverlapInternal:
720 if (last_frame < clicked_regionview->region()->first_frame()) {
721 first_frame = last_frame;
722 last_frame = clicked_regionview->region()->last_frame();
724 last_frame = first_frame;
725 first_frame = clicked_regionview->region()->first_frame();
729 case Evoral::OverlapStart:
730 case Evoral::OverlapEnd:
731 /* nothing to do except add clicked region to selection, since it
732 overlaps with the existing selection in this track.
739 /* click in a track that has no regions selected, so extend vertically
740 to pick out all regions that are defined by the existing selection
745 first_frame = clicked_regionview->region()->position();
746 last_frame = clicked_regionview->region()->last_frame();
748 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
749 if ((*i)->region()->position() < first_frame) {
750 first_frame = (*i)->region()->position();
752 if ((*i)->region()->last_frame() + 1 > last_frame) {
753 last_frame = (*i)->region()->last_frame();
758 /* 2. find all the tracks we should select in */
760 set<RouteTimeAxisView*> relevant_tracks;
762 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
763 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
765 relevant_tracks.insert (r);
769 set<RouteTimeAxisView*> already_in_selection;
771 if (relevant_tracks.empty()) {
773 /* no tracks selected .. thus .. if the
774 regionview we're in isn't selected
775 (i.e. we're about to extend to it), then
776 find all tracks between the this one and
780 if (!selection->selected (clicked_regionview)) {
782 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&clicked_regionview->get_time_axis_view());
786 /* add this track to the ones we will search */
788 relevant_tracks.insert (rtv);
790 /* find the track closest to this one that
791 already a selected region.
794 RouteTimeAxisView* closest = 0;
795 int distance = INT_MAX;
796 int key = rtv->route()->presentation_info().order ();
798 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
800 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
802 if (artv && artv != rtv) {
804 pair<set<RouteTimeAxisView*>::iterator,bool> result;
806 result = already_in_selection.insert (artv);
809 /* newly added to already_in_selection */
811 int d = artv->route()->presentation_info().order ();
815 if (abs (d) < distance) {
825 /* now add all tracks between that one and this one */
827 int okey = closest->route()->presentation_info().order ();
833 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
834 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
835 if (artv && artv != rtv) {
837 int k = artv->route()->presentation_info().order ();
839 if (k >= okey && k <= key) {
841 /* in range but don't add it if
842 it already has tracks selected.
843 this avoids odd selection
844 behaviour that feels wrong.
847 if (find (already_in_selection.begin(),
848 already_in_selection.end(),
849 artv) == already_in_selection.end()) {
851 relevant_tracks.insert (artv);
861 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
862 one that was clicked.
865 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
866 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
869 /* 4. convert to a vector of regions */
871 vector<RegionView*> regions;
873 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
876 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
877 regions.push_back (arv);
881 if (!regions.empty()) {
882 selection->add (regions);
884 } else if (selection->regions.empty() && !selection->selected (clicked_regionview)) {
885 /* ensure that at least the clicked regionview is selected. */
886 selection->set (clicked_regionview);
897 Editor::set_selection (std::list<Selectable*> s, Selection::Operation op)
902 begin_reversible_selection_op (X_("set selection"));
904 case Selection::Toggle:
905 selection->toggle (s);
910 case Selection::Extend:
918 commit_reversible_selection_op () ;
922 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
924 vector<RegionView*> all_equivalent_regions;
926 get_regions_corresponding_to (region, all_equivalent_regions, region->whole_file());
928 if (all_equivalent_regions.empty()) {
932 begin_reversible_selection_op (X_("set selected regions"));
935 case Selection::Toggle:
936 /* XXX this is not correct */
937 selection->toggle (all_equivalent_regions);
940 selection->set (all_equivalent_regions);
942 case Selection::Extend:
943 selection->add (all_equivalent_regions);
946 selection->add (all_equivalent_regions);
950 commit_reversible_selection_op () ;
954 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
957 boost::shared_ptr<Region> r (weak_r.lock());
963 if ((rv = sv->find_view (r)) == 0) {
967 /* don't reset the selection if its something other than
968 a single other region.
971 if (selection->regions.size() > 1) {
975 begin_reversible_selection_op (X_("set selected regions"));
979 commit_reversible_selection_op () ;
984 struct SelectionOrderSorter {
985 bool operator() (TimeAxisView const * const a, TimeAxisView const * const b) const {
986 boost::shared_ptr<Stripable> sa = a->stripable ();
987 boost::shared_ptr<Stripable> sb = b->stripable ();
997 return sa->presentation_info().selection_cnt() < sb->presentation_info().selection_cnt();
1002 Editor::track_selection_changed ()
1004 SelectionOrderSorter cmp;
1005 selection->tracks.sort (cmp);
1007 switch (selection->tracks.size()) {
1011 set_selected_mixer_strip (*(selection->tracks.back()));
1012 if (!_track_selection_change_without_scroll) {
1013 ensure_time_axis_view_is_visible (*(selection->tracks.back()), false);
1018 RouteNotificationListPtr routes (new RouteNotificationList);
1019 StripableNotificationListPtr stripables (new StripableNotificationList);
1021 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1023 bool yn = (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end());
1025 (*i)->set_selected (yn);
1027 TimeAxisView::Children c = (*i)->get_child_list ();
1028 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
1029 (*j)->set_selected (find (selection->tracks.begin(), selection->tracks.end(), j->get()) != selection->tracks.end());
1033 (*i)->reshow_selection (selection->time);
1035 (*i)->hide_selection ();
1040 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*i);
1042 routes->push_back (rtav->route());
1043 stripables->push_back (rtav->route());
1048 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
1050 sensitize_the_right_region_actions (false);
1052 /* notify control protocols */
1054 ControlProtocol::StripableSelectionChanged (stripables);
1056 if (sfbrowser && _session && !_session->deletion_in_progress()) {
1057 uint32_t audio_track_cnt = 0;
1058 uint32_t midi_track_cnt = 0;
1060 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
1061 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*x);
1064 if (atv->is_audio_track()) {
1069 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(*x);
1072 if (mtv->is_midi_track()) {
1079 sfbrowser->reset (audio_track_cnt, midi_track_cnt);
1084 Editor::time_selection_changed ()
1086 /* XXX this is superficially inefficient. Hide the selection in all
1087 * tracks, then show it in all selected tracks.
1089 * However, if you investigate what this actually does, it isn't
1090 * anywhere nearly as bad as it may appear. Remember: nothing is
1091 * redrawn or even recomputed during these two loops - that only
1092 * happens when we next render ...
1095 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1096 (*i)->hide_selection ();
1099 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1100 (*i)->show_selection (selection->time);
1103 if (selection->time.empty()) {
1104 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
1106 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
1109 /* propagate into backend, but only when there is no drag or we are at
1110 * the end of a drag, otherwise this is too expensive (could case a
1111 * locate per mouse motion event.
1114 if (_session && !_drags->active()) {
1115 if (selection->time.length() != 0) {
1116 _session->set_range_selection (selection->time.start(), selection->time.end_frame());
1118 _session->clear_range_selection ();
1123 /** Set all region actions to have a given sensitivity */
1125 Editor::sensitize_all_region_actions (bool s)
1127 Glib::ListHandle<Glib::RefPtr<Action> > all = _region_actions->get_actions ();
1129 for (Glib::ListHandle<Glib::RefPtr<Action> >::iterator i = all.begin(); i != all.end(); ++i) {
1130 (*i)->set_sensitive (s);
1133 _all_region_actions_sensitized = s;
1136 /** Sensitize region-based actions.
1138 * This method is called from whenever we leave the canvas, either by moving
1139 * the pointer out of it, or by popping up a context menu. See
1140 * Editor::{entered,left}_track_canvas() for details there.
1143 Editor::sensitize_the_right_region_actions (bool because_canvas_crossing)
1145 bool have_selection = false;
1146 bool have_entered = false;
1147 bool have_edit_point = false;
1150 // std::cerr << "STRRA: crossing ? " << because_canvas_crossing << " within ? " << within_track_canvas
1153 if (!selection->regions.empty()) {
1154 have_selection = true;
1155 rs = selection->regions;
1158 if (entered_regionview) {
1159 have_entered = true;
1160 rs.add (entered_regionview);
1163 if (rs.empty() && !selection->tracks.empty()) {
1165 /* no selected regions, but some selected tracks.
1168 if (_edit_point == EditAtMouse) {
1169 if (!within_track_canvas) {
1170 /* pointer is not in canvas, so edit point is meaningless */
1171 have_edit_point = false;
1173 /* inside canvas. we don't know where the edit
1174 point will be when an action is invoked, but
1175 assume it could intersect with a region.
1177 have_edit_point = true;
1180 RegionSelection at_edit_point;
1181 framepos_t const where = get_preferred_edit_position (Editing::EDIT_IGNORE_NONE, false, !within_track_canvas);
1182 get_regions_at (at_edit_point, where, selection->tracks);
1183 if (!at_edit_point.empty()) {
1184 have_edit_point = true;
1187 rs.insert (rs.end(), at_edit_point.begin(), at_edit_point.end());
1192 //std::cerr << "\tfinal have selection: " << have_selection
1193 // << " have entered " << have_entered
1194 // << " have edit point " << have_edit_point
1195 // << " EP = " << enum_2_string (_edit_point)
1198 typedef std::map<std::string,RegionAction> RegionActionMap;
1200 _ignore_region_action = true;
1202 for (RegionActionMap::iterator x = region_action_map.begin(); x != region_action_map.end(); ++x) {
1203 RegionActionTarget tgt = x->second.target;
1204 bool sensitive = false;
1206 if ((tgt & SelectedRegions) && have_selection) {
1208 } else if ((tgt & EnteredRegions) && have_entered) {
1210 } else if ((tgt & EditPointRegions) && have_edit_point) {
1214 x->second.action->set_sensitive (sensitive);
1217 /* Look through the regions that are selected and make notes about what we have got */
1219 bool have_audio = false;
1220 bool have_multichannel_audio = false;
1221 bool have_midi = false;
1222 bool have_locked = false;
1223 bool have_unlocked = false;
1224 bool have_video_locked = false;
1225 bool have_video_unlocked = false;
1226 bool have_position_lock_style_audio = false;
1227 bool have_position_lock_style_music = false;
1228 bool have_muted = false;
1229 bool have_unmuted = false;
1230 bool have_opaque = false;
1231 bool have_non_opaque = false;
1232 bool have_not_at_natural_position = false;
1233 bool have_envelope_active = false;
1234 bool have_envelope_inactive = false;
1235 bool have_non_unity_scale_amplitude = false;
1236 bool have_compound_regions = false;
1237 bool have_inactive_fade_in = false;
1238 bool have_inactive_fade_out = false;
1239 bool have_active_fade_in = false;
1240 bool have_active_fade_out = false;
1241 bool have_transients = false;
1243 for (list<RegionView*>::const_iterator i = rs.begin(); i != rs.end(); ++i) {
1245 boost::shared_ptr<Region> r = (*i)->region ();
1246 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
1250 if (ar->n_channels() > 1) {
1251 have_multichannel_audio = true;
1255 if (boost::dynamic_pointer_cast<MidiRegion> (r)) {
1259 if (r->is_compound()) {
1260 have_compound_regions = true;
1266 have_unlocked = true;
1269 if (r->video_locked()) {
1270 have_video_locked = true;
1272 have_video_unlocked = true;
1275 if (r->position_lock_style() == MusicTime) {
1276 have_position_lock_style_music = true;
1278 have_position_lock_style_audio = true;
1284 have_unmuted = true;
1290 have_non_opaque = true;
1293 if (!r->at_natural_position()) {
1294 have_not_at_natural_position = true;
1297 if (r->has_transients ()){
1298 have_transients = true;
1302 if (ar->envelope_active()) {
1303 have_envelope_active = true;
1305 have_envelope_inactive = true;
1308 if (ar->scale_amplitude() != 1) {
1309 have_non_unity_scale_amplitude = true;
1312 if (ar->fade_in_active ()) {
1313 have_active_fade_in = true;
1315 have_inactive_fade_in = true;
1318 if (ar->fade_out_active ()) {
1319 have_active_fade_out = true;
1321 have_inactive_fade_out = true;
1326 _region_actions->get_action("split-region-at-transients")->set_sensitive (have_transients);
1328 if (rs.size() > 1) {
1329 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1330 _region_actions->get_action("show-region-properties")->set_sensitive (false);
1331 _region_actions->get_action("rename-region")->set_sensitive (false);
1333 /* XXX need to check whether there is than 1 per
1334 playlist, because otherwise this makes no sense.
1336 _region_actions->get_action("combine-regions")->set_sensitive (true);
1338 _region_actions->get_action("combine-regions")->set_sensitive (false);
1340 } else if (rs.size() == 1) {
1341 _region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
1342 _region_actions->get_action("close-region-gaps")->set_sensitive (false);
1343 _region_actions->get_action("combine-regions")->set_sensitive (false);
1346 if (!have_multichannel_audio) {
1347 _region_actions->get_action("split-multichannel-region")->set_sensitive (false);
1351 editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (false);
1352 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1353 _region_actions->get_action("quantize-region")->set_sensitive (false);
1354 _region_actions->get_action("legatize-region")->set_sensitive (false);
1355 _region_actions->get_action("remove-overlap")->set_sensitive (false);
1356 _region_actions->get_action("transform-region")->set_sensitive (false);
1357 _region_actions->get_action("fork-region")->set_sensitive (false);
1358 _region_actions->get_action("insert-patch-change-context")->set_sensitive (false);
1359 _region_actions->get_action("insert-patch-change")->set_sensitive (false);
1360 _region_actions->get_action("transpose-region")->set_sensitive (false);
1362 editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (true);
1363 /* others were already marked sensitive */
1366 /* ok, moving along... */
1368 if (have_compound_regions) {
1369 _region_actions->get_action("uncombine-regions")->set_sensitive (true);
1371 _region_actions->get_action("uncombine-regions")->set_sensitive (false);
1376 if (have_envelope_active && !have_envelope_inactive) {
1377 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active ();
1378 } else if (have_envelope_active && have_envelope_inactive) {
1379 // Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_inconsistent ();
1384 _region_actions->get_action("loudness-analyze-region")->set_sensitive (false);
1385 _region_actions->get_action("spectral-analyze-region")->set_sensitive (false);
1386 _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
1387 _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
1388 _region_actions->get_action("pitch-shift-region")->set_sensitive (false);
1389 _region_actions->get_action("strip-region-silence")->set_sensitive (false);
1390 _region_actions->get_action("show-rhythm-ferret")->set_sensitive (false);
1394 if (!have_non_unity_scale_amplitude || !have_audio) {
1395 _region_actions->get_action("reset-region-scale-amplitude")->set_sensitive (false);
1398 Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"));
1399 a->set_active (have_locked && !have_unlocked);
1400 if (have_locked && have_unlocked) {
1401 // a->set_inconsistent ();
1404 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-video-lock"));
1405 a->set_active (have_video_locked && !have_video_unlocked);
1406 if (have_video_locked && have_video_unlocked) {
1407 // a->set_inconsistent ();
1410 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
1411 a->set_active (have_position_lock_style_music && !have_position_lock_style_audio);
1413 vector<Widget*> proxies = a->get_proxies();
1414 for (vector<Widget*>::iterator p = proxies.begin(); p != proxies.end(); ++p) {
1415 Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (*p);
1417 cmi->set_inconsistent (have_position_lock_style_music && have_position_lock_style_audio);
1421 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"));
1422 a->set_active (have_muted && !have_unmuted);
1423 if (have_muted && have_unmuted) {
1424 // a->set_inconsistent ();
1427 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"));
1428 a->set_active (have_opaque && !have_non_opaque);
1429 if (have_opaque && have_non_opaque) {
1430 // a->set_inconsistent ();
1433 if (!have_not_at_natural_position) {
1434 _region_actions->get_action("naturalize-region")->set_sensitive (false);
1437 /* XXX: should also check that there is a track of the appropriate type for the selected region */
1438 if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
1439 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (false);
1441 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (true);
1444 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-in"));
1445 a->set_active (have_active_fade_in && !have_inactive_fade_in);
1446 if (have_active_fade_in && have_inactive_fade_in) {
1447 // a->set_inconsistent ();
1450 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-out"));
1451 a->set_active (have_active_fade_out && !have_inactive_fade_out);
1453 if (have_active_fade_out && have_inactive_fade_out) {
1454 // a->set_inconsistent ();
1457 bool const have_active_fade = have_active_fade_in || have_active_fade_out;
1458 bool const have_inactive_fade = have_inactive_fade_in || have_inactive_fade_out;
1460 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fades"));
1461 a->set_active (have_active_fade && !have_inactive_fade);
1463 if (have_active_fade && have_inactive_fade) {
1464 // a->set_inconsistent ();
1467 _ignore_region_action = false;
1469 _all_region_actions_sensitized = false;
1473 Editor::region_selection_changed ()
1475 _regions->block_change_connection (true);
1476 editor_regions_selection_changed_connection.block(true);
1478 if (_region_selection_change_updates_region_list) {
1479 _regions->unselect_all ();
1482 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1483 (*i)->set_selected_regionviews (selection->regions);
1486 if (_region_selection_change_updates_region_list) {
1487 _regions->set_selected (selection->regions);
1490 _regions->block_change_connection (false);
1491 editor_regions_selection_changed_connection.block(false);
1493 sensitize_the_right_region_actions (false);
1495 /* propagate into backend */
1498 if (!selection->regions.empty()) {
1499 _session->set_object_selection (selection->regions.start(), selection->regions.end_frame());
1501 _session->clear_object_selection ();
1508 Editor::point_selection_changed ()
1510 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1511 (*i)->set_selected_points (selection->points);
1516 Editor::select_all_in_track (Selection::Operation op)
1518 list<Selectable *> touched;
1520 if (!clicked_routeview) {
1524 begin_reversible_selection_op (X_("Select All in Track"));
1526 clicked_routeview->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1529 case Selection::Toggle:
1530 selection->add (touched);
1532 case Selection::Set:
1533 selection->set (touched);
1535 case Selection::Extend:
1536 /* meaningless, because we're selecting everything */
1538 case Selection::Add:
1539 selection->add (touched);
1543 commit_reversible_selection_op ();
1547 Editor::select_all_internal_edit (Selection::Operation)
1549 bool selected = false;
1551 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1552 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1554 mrv->select_all_notes ();
1559 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(entered_regionview);
1561 mrv->select_all_notes ();
1569 Editor::select_all_objects (Selection::Operation op)
1571 list<Selectable *> touched;
1573 TrackViewList ts = track_views;
1575 if (internal_editing() && select_all_internal_edit(op)) {
1576 return; // Selected notes
1579 for (TrackViewList::iterator iter = ts.begin(); iter != ts.end(); ++iter) {
1580 if ((*iter)->hidden()) {
1583 (*iter)->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1584 selection->add (*iter);
1588 begin_reversible_selection_op (X_("select all"));
1590 case Selection::Add:
1591 selection->add (touched);
1593 case Selection::Toggle:
1594 selection->add (touched);
1596 case Selection::Set:
1597 selection->set (touched);
1599 case Selection::Extend:
1600 /* meaningless, because we're selecting everything */
1603 commit_reversible_selection_op ();
1607 Editor::invert_selection_in_track ()
1609 list<Selectable *> touched;
1611 if (!clicked_routeview) {
1615 begin_reversible_selection_op (X_("Invert Selection in Track"));
1616 clicked_routeview->get_inverted_selectables (*selection, touched);
1617 selection->set (touched);
1618 commit_reversible_selection_op ();
1622 Editor::invert_selection ()
1624 list<Selectable *> touched;
1626 if (internal_editing()) {
1627 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1628 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1630 mrv->invert_selection ();
1636 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1637 if ((*iter)->hidden()) {
1640 (*iter)->get_inverted_selectables (*selection, touched);
1643 begin_reversible_selection_op (X_("Invert Selection"));
1644 selection->set (touched);
1645 commit_reversible_selection_op ();
1648 /** @param start Start time in session frames.
1649 * @param end End time in session frames.
1650 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
1651 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
1652 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
1653 * within the region are already selected.
1656 Editor::select_all_within (framepos_t start, framepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected)
1658 list<Selectable*> found;
1660 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1662 if ((*iter)->hidden()) {
1666 (*iter)->get_selectables (start, end, top, bot, found);
1669 if (found.empty()) {
1670 selection->clear_objects();
1671 selection->clear_time ();
1675 if (preserve_if_selected && op != Selection::Toggle) {
1676 list<Selectable*>::iterator i = found.begin();
1677 while (i != found.end() && (*i)->selected()) {
1681 if (i == found.end()) {
1686 begin_reversible_selection_op (X_("select all within"));
1688 case Selection::Add:
1689 selection->add (found);
1691 case Selection::Toggle:
1692 selection->toggle (found);
1694 case Selection::Set:
1695 selection->set (found);
1697 case Selection::Extend:
1698 /* not defined yet */
1702 commit_reversible_selection_op ();
1706 Editor::set_selection_from_region ()
1708 if (selection->regions.empty()) {
1712 /* find all the tracks that have selected regions */
1714 set<TimeAxisView*> tracks;
1716 for (RegionSelection::const_iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
1717 tracks.insert (&(*r)->get_time_axis_view());
1721 tvl.insert (tvl.end(), tracks.begin(), tracks.end());
1723 /* select range (this will clear the region selection) */
1725 selection->set (selection->regions.start(), selection->regions.end_frame());
1727 /* and select the tracks */
1729 selection->set (tvl);
1731 if (!get_smart_mode () || !mouse_mode == Editing::MouseObject) {
1732 set_mouse_mode (Editing::MouseRange, false);
1737 Editor::set_selection_from_punch()
1741 if ((location = _session->locations()->auto_punch_location()) == 0) {
1745 set_selection_from_range (*location);
1749 Editor::set_selection_from_loop()
1753 if ((location = _session->locations()->auto_loop_location()) == 0) {
1756 set_selection_from_range (*location);
1760 Editor::set_selection_from_range (Location& loc)
1762 begin_reversible_selection_op (X_("set selection from range"));
1763 selection->set (loc.start(), loc.end());
1764 commit_reversible_selection_op ();
1766 if (!get_smart_mode () || mouse_mode != Editing::MouseObject) {
1767 set_mouse_mode (MouseRange, false);
1772 Editor::select_all_selectables_using_time_selection ()
1774 list<Selectable *> touched;
1776 if (selection->time.empty()) {
1780 framepos_t start = selection->time[clicked_selection].start;
1781 framepos_t end = selection->time[clicked_selection].end;
1783 if (end - start < 1) {
1789 if (selection->tracks.empty()) {
1792 ts = &selection->tracks;
1795 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1796 if ((*iter)->hidden()) {
1799 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1802 begin_reversible_selection_op (X_("select all from range"));
1803 selection->set (touched);
1804 commit_reversible_selection_op ();
1809 Editor::select_all_selectables_using_punch()
1811 Location* location = _session->locations()->auto_punch_location();
1812 list<Selectable *> touched;
1814 if (location == 0 || (location->end() - location->start() <= 1)) {
1821 if (selection->tracks.empty()) {
1824 ts = &selection->tracks;
1827 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1828 if ((*iter)->hidden()) {
1831 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1833 begin_reversible_selection_op (X_("select all from punch"));
1834 selection->set (touched);
1835 commit_reversible_selection_op ();
1840 Editor::select_all_selectables_using_loop()
1842 Location* location = _session->locations()->auto_loop_location();
1843 list<Selectable *> touched;
1845 if (location == 0 || (location->end() - location->start() <= 1)) {
1852 if (selection->tracks.empty()) {
1855 ts = &selection->tracks;
1858 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1859 if ((*iter)->hidden()) {
1862 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1864 begin_reversible_selection_op (X_("select all from loop"));
1865 selection->set (touched);
1866 commit_reversible_selection_op ();
1871 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1875 list<Selectable *> touched;
1878 start = cursor->current_frame();
1879 end = _session->current_end_frame();
1881 if (cursor->current_frame() > 0) {
1883 end = cursor->current_frame() - 1;
1889 if (internal_editing()) {
1890 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1891 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1893 mrv->select_range (start, end);
1900 begin_reversible_selection_op (X_("select all after cursor"));
1902 begin_reversible_selection_op (X_("select all before cursor"));
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 (start, end, 0, DBL_MAX, touched);
1919 selection->set (touched);
1920 commit_reversible_selection_op ();
1924 Editor::select_all_selectables_using_edit (bool after, bool from_context_menu)
1928 list<Selectable *> touched;
1931 start = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu);
1932 end = _session->current_end_frame();
1934 if ((end = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu)) > 1) {
1942 if (internal_editing()) {
1943 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1944 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1945 mrv->select_range (start, end);
1951 begin_reversible_selection_op (X_("select all after edit"));
1953 begin_reversible_selection_op (X_("select all before edit"));
1958 if (selection->tracks.empty()) {
1961 ts = &selection->tracks;
1964 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1965 if ((*iter)->hidden()) {
1968 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1970 selection->set (touched);
1971 commit_reversible_selection_op ();
1975 Editor::select_all_selectables_between (bool within)
1979 list<Selectable *> touched;
1981 if (!get_edit_op_range (start, end)) {
1985 if (internal_editing()) {
1986 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1987 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1988 mrv->select_range (start, end);
1995 if (selection->tracks.empty()) {
1998 ts = &selection->tracks;
2001 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
2002 if ((*iter)->hidden()) {
2005 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched, within);
2008 begin_reversible_selection_op (X_("Select all Selectables Between"));
2009 selection->set (touched);
2010 commit_reversible_selection_op ();
2014 Editor::select_range_between ()
2019 if ( !selection->time.empty() ) {
2020 selection->clear_time ();
2023 if (!get_edit_op_range (start, end)) {
2027 if (!get_smart_mode () || mouse_mode != Editing::MouseObject) {
2028 set_mouse_mode (MouseRange, false);
2031 begin_reversible_selection_op (X_("Select Range Between"));
2032 selection->set (start, end);
2033 commit_reversible_selection_op ();
2037 Editor::get_edit_op_range (framepos_t& start, framepos_t& end) const
2042 /* if an explicit range exists, use it */
2044 if ( (mouse_mode == MouseRange || get_smart_mode() ) && !selection->time.empty()) {
2045 /* we know that these are ordered */
2046 start = selection->time.start();
2047 end = selection->time.end_frame();
2055 // if (!mouse_frame (m, ignored)) {
2056 // /* mouse is not in a canvas, try playhead+selected marker.
2057 // this is probably most true when using menus.
2060 // if (selection->markers.empty()) {
2064 // start = selection->markers.front()->position();
2065 // end = _session->audible_frame();
2069 // switch (_edit_point) {
2070 // case EditAtPlayhead:
2071 // if (selection->markers.empty()) {
2072 // /* use mouse + playhead */
2074 // end = _session->audible_frame();
2076 // /* use playhead + selected marker */
2077 // start = _session->audible_frame();
2078 // end = selection->markers.front()->position();
2082 // case EditAtMouse:
2083 // /* use mouse + selected marker */
2084 // if (selection->markers.empty()) {
2086 // end = _session->audible_frame();
2088 // start = selection->markers.front()->position();
2093 // case EditAtSelectedMarker:
2094 // /* use mouse + selected marker */
2095 // if (selection->markers.empty()) {
2097 // MessageDialog win (_("No edit range defined"),
2102 // win.set_secondary_text (
2103 // _("the edit point is Selected Marker\nbut there is no selected marker."));
2106 // win.set_default_response (RESPONSE_CLOSE);
2107 // win.set_position (Gtk::WIN_POS_MOUSE);
2112 // return false; // NO RANGE
2114 // start = selection->markers.front()->position();
2120 // if (start == end) {
2124 // if (start > end) {
2125 // swap (start, end);
2128 /* turn range into one delimited by start...end,
2138 Editor::deselect_all ()
2140 begin_reversible_selection_op (X_("Deselect All"));
2141 selection->clear ();
2142 commit_reversible_selection_op ();
2146 Editor::select_range (framepos_t s, framepos_t e)
2148 begin_reversible_selection_op (X_("Select Range"));
2149 selection->add (clicked_axisview);
2150 selection->time.clear ();
2151 long ret = selection->set (s, e);
2152 commit_reversible_selection_op ();