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"
25 #include "ardour/midi_region.h"
26 #include "ardour/playlist.h"
27 #include "ardour/profile.h"
28 #include "ardour/route_group.h"
29 #include "ardour/session.h"
31 #include "control_protocol/control_protocol.h"
33 #include "editor_drag.h"
36 #include "audio_time_axis.h"
37 #include "audio_region_view.h"
38 #include "audio_streamview.h"
39 #include "automation_line.h"
40 #include "control_point.h"
41 #include "editor_regions.h"
42 #include "editor_cursors.h"
43 #include "midi_region_view.h"
49 using namespace ARDOUR;
53 using namespace Gtkmm2ext;
54 using namespace Editing;
56 struct TrackViewByPositionSorter
58 bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
59 return a->y_position() < b->y_position();
64 Editor::extend_selection_to_track (TimeAxisView& view)
66 if (selection->selected (&view)) {
67 /* already selected, do nothing */
71 if (selection->tracks.empty()) {
73 if (!selection->selected (&view)) {
74 selection->set (&view);
81 /* something is already selected, so figure out which range of things to add */
83 TrackViewList to_be_added;
84 TrackViewList sorted = track_views;
85 TrackViewByPositionSorter cmp;
86 bool passed_clicked = false;
91 if (!selection->selected (&view)) {
92 to_be_added.push_back (&view);
95 /* figure out if we should go forward or backwards */
97 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
100 passed_clicked = true;
103 if (selection->selected (*i)) {
104 if (passed_clicked) {
113 passed_clicked = false;
117 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
120 passed_clicked = true;
124 if (passed_clicked) {
125 if ((*i)->hidden()) {
128 if (selection->selected (*i)) {
130 } else if (!(*i)->hidden()) {
131 to_be_added.push_back (*i);
138 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
141 passed_clicked = true;
145 if (passed_clicked) {
147 if ((*r)->hidden()) {
151 if (selection->selected (*r)) {
153 } else if (!(*r)->hidden()) {
154 to_be_added.push_back (*r);
160 if (!to_be_added.empty()) {
161 selection->add (to_be_added);
169 Editor::select_all_tracks ()
171 TrackViewList visible_views;
172 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
173 if ((*i)->marked_for_display()) {
174 visible_views.push_back (*i);
177 selection->set (visible_views);
180 /** Select clicked_axisview, unless there are no currently selected
181 * tracks, in which case nothing will happen unless `force' is true.
184 Editor::set_selected_track_as_side_effect (Selection::Operation op)
186 if (!clicked_axisview) {
190 RouteGroup* group = NULL;
191 if (clicked_routeview) {
192 group = clicked_routeview->route()->route_group();
196 case Selection::Toggle:
197 if (selection->selected (clicked_axisview)) {
198 if (group && group->is_active()) {
199 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
200 if ((*i)->route_group() == group) {
201 selection->remove(*i);
205 selection->remove (clicked_axisview);
208 if (group && group->is_active()) {
209 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
210 if ((*i)->route_group() == group) {
215 selection->add (clicked_axisview);
221 if (group && group->is_active()) {
222 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
223 if ((*i)->route_group() == group) {
228 selection->add (clicked_axisview);
234 if (group && group->is_active()) {
235 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
236 if ((*i)->route_group() == group) {
241 selection->set (clicked_axisview);
245 case Selection::Extend:
252 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
254 begin_reversible_selection_op (X_("Set Selected Track"));
257 case Selection::Toggle:
258 if (selection->selected (&view)) {
260 selection->remove (&view);
263 selection->add (&view);
268 if (!selection->selected (&view)) {
269 selection->add (&view);
274 selection->set (&view);
277 case Selection::Extend:
278 extend_selection_to_track (view);
282 commit_reversible_selection_op ();
286 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
288 if (!clicked_routeview) {
296 set_selected_track (*clicked_routeview, op, no_remove);
300 Editor::set_selected_control_point_from_click (bool press, Selection::Operation op)
302 if (!clicked_control_point) {
310 if (!selection->selected (clicked_control_point)) {
311 selection->set (clicked_control_point);
314 /* clicked on an already selected point */
318 if (selection->points.size() > 1) {
319 selection->set (clicked_control_point);
328 selection->add (clicked_control_point);
332 case Selection::Toggle:
334 /* This is a bit of a hack; if we Primary-Click-Drag a control
335 point (for push drag) we want the point we clicked on to be
336 selected, otherwise we end up confusingly dragging an
337 unselected point. So here we ensure that the point is selected
338 after the press, and if we subsequently get a release (meaning no
339 drag occurred) we set things up so that the toggle has happened.
341 if (press && !selection->selected (clicked_control_point)) {
342 /* This is the button press, and the control point is not selected; make it so,
343 in case this press leads to a drag. Also note that having done this, we don't
344 need to toggle again on release.
346 selection->toggle (clicked_control_point);
347 _control_point_toggled_on_press = true;
349 } else if (!press && !_control_point_toggled_on_press) {
350 /* This is the release, and the point wasn't toggled on the press, so do it now */
351 selection->toggle (clicked_control_point);
355 _control_point_toggled_on_press = false;
358 case Selection::Extend:
367 Editor::get_onscreen_tracks (TrackViewList& tvl)
369 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
370 if ((*i)->y_position() < _visible_canvas_height) {
376 /** Call a slot for a given `basis' track and also for any track that is in the same
377 * active route group with a particular set of properties.
379 * @param sl Slot to call.
380 * @param basis Basis track.
381 * @param prop Properties that active edit groups must share to be included in the map.
385 Editor::mapover_tracks (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
387 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
389 if (route_basis == 0) {
393 set<RouteTimeAxisView*> tracks;
394 tracks.insert (route_basis);
396 RouteGroup* group = route_basis->route()->route_group();
398 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id) ) {
400 /* the basis is a member of an active route group, with the appropriate
401 properties; find other members */
403 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
404 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
405 if (v && v->route()->route_group() == group) {
412 uint32_t const sz = tracks.size ();
414 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
419 /** Call a slot for a given `basis' track and also for any track that is in the same
420 * active route group with a particular set of properties.
422 * @param sl Slot to call.
423 * @param basis Basis track.
424 * @param prop Properties that active edit groups must share to be included in the map.
428 Editor::mapover_tracks_with_unique_playlists (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
430 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
431 set<boost::shared_ptr<Playlist> > playlists;
433 if (route_basis == 0) {
437 set<RouteTimeAxisView*> tracks;
438 tracks.insert (route_basis);
440 RouteGroup* group = route_basis->route()->route_group(); // could be null, not a problem
442 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id) ) {
444 /* the basis is a member of an active route group, with the appropriate
445 properties; find other members */
447 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
448 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
450 if (v && v->route()->route_group() == group) {
452 boost::shared_ptr<Track> t = v->track();
454 if (playlists.insert (t->playlist()).second) {
455 /* haven't seen this playlist yet */
459 /* not actually a "Track", but a timeaxis view that
460 we should mapover anyway.
469 uint32_t const sz = tracks.size ();
471 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
477 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
479 boost::shared_ptr<Playlist> pl;
480 vector<boost::shared_ptr<Region> > results;
482 boost::shared_ptr<Track> tr;
484 if ((tr = tv.track()) == 0) {
489 if (&tv == &basis->get_time_axis_view()) {
490 /* looking in same track as the original */
494 if ((pl = tr->playlist()) != 0) {
495 pl->get_equivalent_regions (basis->region(), results);
498 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
499 if ((marv = tv.view()->find_view (*ir)) != 0) {
500 all_equivs->push_back (marv);
506 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, PBD::PropertyID property) const
508 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);
510 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
512 equivalent_regions.push_back (basis);
516 Editor::get_equivalent_regions (RegionSelection & basis, PBD::PropertyID prop) const
518 RegionSelection equivalent;
520 for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
522 vector<RegionView*> eq;
524 mapover_tracks_with_unique_playlists (
525 sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
526 &(*i)->get_time_axis_view(), prop);
528 for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
539 Editor::get_regionview_count_from_region_list (boost::shared_ptr<Region> region)
541 int region_count = 0;
543 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
545 RouteTimeAxisView* tatv;
547 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
549 boost::shared_ptr<Playlist> pl;
550 vector<boost::shared_ptr<Region> > results;
552 boost::shared_ptr<Track> tr;
554 if ((tr = tatv->track()) == 0) {
559 if ((pl = (tr->playlist())) != 0) {
560 pl->get_region_list_equivalent_regions (region, results);
563 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
564 if ((marv = tatv->view()->find_view (*ir)) != 0) {
577 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op)
579 vector<RegionView*> all_equivalent_regions;
582 if (!clicked_regionview || !clicked_routeview) {
587 button_release_can_deselect = false;
590 if (op == Selection::Toggle || op == Selection::Set) {
593 case Selection::Toggle:
594 if (selection->selected (clicked_regionview)) {
597 /* whatever was clicked was selected already; do nothing here but allow
598 the button release to deselect it
601 button_release_can_deselect = true;
604 if (button_release_can_deselect) {
606 /* just remove this one region, but only on a permitted button release */
608 selection->remove (clicked_regionview);
611 /* no more deselect action on button release till a new press
612 finds an already selected object.
615 button_release_can_deselect = false;
623 if (selection->selected (clicked_routeview)) {
624 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
626 all_equivalent_regions.push_back (clicked_regionview);
629 /* add all the equivalent regions, but only on button press */
631 if (!all_equivalent_regions.empty()) {
635 selection->add (all_equivalent_regions);
641 if (!selection->selected (clicked_regionview)) {
642 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
643 selection->set (all_equivalent_regions);
646 /* clicked on an already selected region */
650 if (selection->regions.size() > 1) {
651 /* collapse region selection down to just this one region (and its equivalents) */
652 get_equivalent_regions(clicked_regionview, all_equivalent_regions, ARDOUR::Properties::group_select.property_id);
653 selection->set(all_equivalent_regions);
665 } else if (op == Selection::Extend) {
667 list<Selectable*> results;
668 framepos_t last_frame;
669 framepos_t first_frame;
670 bool same_track = false;
672 /* 1. find the last selected regionview in the track that was clicked in */
675 first_frame = max_framepos;
677 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
678 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
680 if ((*x)->region()->last_frame() > last_frame) {
681 last_frame = (*x)->region()->last_frame();
684 if ((*x)->region()->first_frame() < first_frame) {
685 first_frame = (*x)->region()->first_frame();
694 /* 2. figure out the boundaries for our search for new objects */
696 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
697 case Evoral::OverlapNone:
698 if (last_frame < clicked_regionview->region()->first_frame()) {
699 first_frame = last_frame;
700 last_frame = clicked_regionview->region()->last_frame();
702 last_frame = first_frame;
703 first_frame = clicked_regionview->region()->first_frame();
707 case Evoral::OverlapExternal:
708 if (last_frame < clicked_regionview->region()->first_frame()) {
709 first_frame = last_frame;
710 last_frame = clicked_regionview->region()->last_frame();
712 last_frame = first_frame;
713 first_frame = clicked_regionview->region()->first_frame();
717 case Evoral::OverlapInternal:
718 if (last_frame < clicked_regionview->region()->first_frame()) {
719 first_frame = last_frame;
720 last_frame = clicked_regionview->region()->last_frame();
722 last_frame = first_frame;
723 first_frame = clicked_regionview->region()->first_frame();
727 case Evoral::OverlapStart:
728 case Evoral::OverlapEnd:
729 /* nothing to do except add clicked region to selection, since it
730 overlaps with the existing selection in this track.
737 /* click in a track that has no regions selected, so extend vertically
738 to pick out all regions that are defined by the existing selection
743 first_frame = clicked_regionview->region()->position();
744 last_frame = clicked_regionview->region()->last_frame();
746 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
747 if ((*i)->region()->position() < first_frame) {
748 first_frame = (*i)->region()->position();
750 if ((*i)->region()->last_frame() + 1 > last_frame) {
751 last_frame = (*i)->region()->last_frame();
756 /* 2. find all the tracks we should select in */
758 set<RouteTimeAxisView*> relevant_tracks;
760 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
761 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
763 relevant_tracks.insert (r);
767 set<RouteTimeAxisView*> already_in_selection;
769 if (relevant_tracks.empty()) {
771 /* no tracks selected .. thus .. if the
772 regionview we're in isn't selected
773 (i.e. we're about to extend to it), then
774 find all tracks between the this one and
778 if (!selection->selected (clicked_regionview)) {
780 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&clicked_regionview->get_time_axis_view());
784 /* add this track to the ones we will search */
786 relevant_tracks.insert (rtv);
788 /* find the track closest to this one that
789 already a selected region.
792 RouteTimeAxisView* closest = 0;
793 int distance = INT_MAX;
794 int key = rtv->route()->presentation_info().order ();
796 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
798 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
800 if (artv && artv != rtv) {
802 pair<set<RouteTimeAxisView*>::iterator,bool> result;
804 result = already_in_selection.insert (artv);
807 /* newly added to already_in_selection */
809 int d = artv->route()->presentation_info().order ();
813 if (abs (d) < distance) {
823 /* now add all tracks between that one and this one */
825 int okey = closest->route()->presentation_info().order ();
831 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
832 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
833 if (artv && artv != rtv) {
835 int k = artv->route()->presentation_info().order ();
837 if (k >= okey && k <= key) {
839 /* in range but don't add it if
840 it already has tracks selected.
841 this avoids odd selection
842 behaviour that feels wrong.
845 if (find (already_in_selection.begin(),
846 already_in_selection.end(),
847 artv) == already_in_selection.end()) {
849 relevant_tracks.insert (artv);
859 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
860 one that was clicked.
863 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
864 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
867 /* 4. convert to a vector of regions */
869 vector<RegionView*> regions;
871 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
874 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
875 regions.push_back (arv);
879 if (!regions.empty()) {
880 selection->add (regions);
882 } else if (selection->regions.empty() && !selection->selected (clicked_regionview)) {
883 /* ensure that at least the clicked regionview is selected. */
884 selection->set (clicked_regionview);
896 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
898 vector<RegionView*> all_equivalent_regions;
900 get_regions_corresponding_to (region, all_equivalent_regions, region->whole_file());
902 if (all_equivalent_regions.empty()) {
906 begin_reversible_selection_op (X_("set selected regions"));
909 case Selection::Toggle:
910 /* XXX this is not correct */
911 selection->toggle (all_equivalent_regions);
914 selection->set (all_equivalent_regions);
916 case Selection::Extend:
917 selection->add (all_equivalent_regions);
920 selection->add (all_equivalent_regions);
924 commit_reversible_selection_op () ;
928 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
931 boost::shared_ptr<Region> r (weak_r.lock());
937 if ((rv = sv->find_view (r)) == 0) {
941 /* don't reset the selection if its something other than
942 a single other region.
945 if (selection->regions.size() > 1) {
949 begin_reversible_selection_op (X_("set selected regions"));
953 commit_reversible_selection_op () ;
959 Editor::track_selection_changed ()
961 switch (selection->tracks.size()) {
965 /* last element in selection list is the most recently
966 * selected, because we always append to that list.
968 set_selected_mixer_strip (*(selection->tracks.back()));
969 ensure_time_axis_view_is_visible (*(selection->tracks.back()), false);
973 RouteNotificationListPtr routes (new RouteNotificationList);
974 StripableNotificationListPtr stripables (new StripableNotificationList);
976 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
978 bool yn = (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end());
980 (*i)->set_selected (yn);
982 TimeAxisView::Children c = (*i)->get_child_list ();
983 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
984 (*j)->set_selected (find (selection->tracks.begin(), selection->tracks.end(), j->get()) != selection->tracks.end());
988 (*i)->reshow_selection (selection->time);
990 (*i)->hide_selection ();
995 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*i);
997 routes->push_back (rtav->route());
998 stripables->push_back (rtav->route());
1003 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
1005 sensitize_the_right_region_actions (false);
1007 /* notify control protocols */
1009 ControlProtocol::StripableSelectionChanged (stripables);
1011 if (sfbrowser && _session && !_session->deletion_in_progress()) {
1012 uint32_t audio_track_cnt = 0;
1013 uint32_t midi_track_cnt = 0;
1015 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
1016 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*x);
1019 if (atv->is_audio_track()) {
1024 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(*x);
1027 if (mtv->is_midi_track()) {
1034 sfbrowser->reset (audio_track_cnt, midi_track_cnt);
1039 Editor::time_selection_changed ()
1041 /* XXX this is superficially inefficient. Hide the selection in all
1042 * tracks, then show it in all selected tracks.
1044 * However, if you investigate what this actually does, it isn't
1045 * anywhere nearly as bad as it may appear. Remember: nothing is
1046 * redrawn or even recomputed during these two loops - that only
1047 * happens when we next render ...
1050 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1051 (*i)->hide_selection ();
1054 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1055 (*i)->show_selection (selection->time);
1058 if (selection->time.empty()) {
1059 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
1061 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
1064 /* propagate into backend, but only when there is no drag or we are at
1065 * the end of a drag, otherwise this is too expensive (could case a
1066 * locate per mouse motion event.
1069 if (_session && !_drags->active()) {
1070 if (selection->time.length() != 0) {
1071 _session->set_range_selection (selection->time.start(), selection->time.end_frame());
1073 _session->clear_range_selection ();
1078 /** Set all region actions to have a given sensitivity */
1080 Editor::sensitize_all_region_actions (bool s)
1082 Glib::ListHandle<Glib::RefPtr<Action> > all = _region_actions->get_actions ();
1084 for (Glib::ListHandle<Glib::RefPtr<Action> >::iterator i = all.begin(); i != all.end(); ++i) {
1085 (*i)->set_sensitive (s);
1088 _all_region_actions_sensitized = s;
1091 /** Sensitize region-based actions.
1093 * This method is called from whenever we leave the canvas, either by moving
1094 * the pointer out of it, or by popping up a context menu. See
1095 * Editor::{entered,left}_track_canvas() for details there.
1098 Editor::sensitize_the_right_region_actions (bool because_canvas_crossing)
1100 bool have_selection = false;
1101 bool have_entered = false;
1102 bool have_edit_point = false;
1105 // std::cerr << "STRRA: crossing ? " << because_canvas_crossing << " within ? " << within_track_canvas
1108 if (!selection->regions.empty()) {
1109 have_selection = true;
1110 rs = selection->regions;
1113 if (entered_regionview) {
1114 have_entered = true;
1115 rs.add (entered_regionview);
1118 if (rs.empty() && !selection->tracks.empty()) {
1120 /* no selected regions, but some selected tracks.
1123 if (_edit_point == EditAtMouse) {
1124 if (!within_track_canvas) {
1125 /* pointer is not in canvas, so edit point is meaningless */
1126 have_edit_point = false;
1128 /* inside canvas. we don't know where the edit
1129 point will be when an action is invoked, but
1130 assume it could intersect with a region.
1132 have_edit_point = true;
1135 RegionSelection at_edit_point;
1136 framepos_t const where = get_preferred_edit_position (Editing::EDIT_IGNORE_NONE, false, !within_track_canvas);
1137 get_regions_at (at_edit_point, where, selection->tracks);
1138 if (!at_edit_point.empty()) {
1139 have_edit_point = true;
1142 rs.insert (rs.end(), at_edit_point.begin(), at_edit_point.end());
1147 //std::cerr << "\tfinal have selection: " << have_selection
1148 // << " have entered " << have_entered
1149 // << " have edit point " << have_edit_point
1150 // << " EP = " << enum_2_string (_edit_point)
1153 typedef std::map<std::string,RegionAction> RegionActionMap;
1155 _ignore_region_action = true;
1157 for (RegionActionMap::iterator x = region_action_map.begin(); x != region_action_map.end(); ++x) {
1158 RegionActionTarget tgt = x->second.target;
1159 bool sensitive = false;
1161 if ((tgt & SelectedRegions) && have_selection) {
1163 } else if ((tgt & EnteredRegions) && have_entered) {
1165 } else if ((tgt & EditPointRegions) && have_edit_point) {
1169 x->second.action->set_sensitive (sensitive);
1172 /* Look through the regions that are selected and make notes about what we have got */
1174 bool have_audio = false;
1175 bool have_multichannel_audio = false;
1176 bool have_midi = false;
1177 bool have_locked = false;
1178 bool have_unlocked = false;
1179 bool have_video_locked = false;
1180 bool have_video_unlocked = false;
1181 bool have_position_lock_style_audio = false;
1182 bool have_position_lock_style_music = false;
1183 bool have_muted = false;
1184 bool have_unmuted = false;
1185 bool have_opaque = false;
1186 bool have_non_opaque = false;
1187 bool have_not_at_natural_position = false;
1188 bool have_envelope_active = false;
1189 bool have_envelope_inactive = false;
1190 bool have_non_unity_scale_amplitude = false;
1191 bool have_compound_regions = false;
1192 bool have_inactive_fade_in = false;
1193 bool have_inactive_fade_out = false;
1194 bool have_active_fade_in = false;
1195 bool have_active_fade_out = false;
1196 bool have_transients = false;
1198 for (list<RegionView*>::const_iterator i = rs.begin(); i != rs.end(); ++i) {
1200 boost::shared_ptr<Region> r = (*i)->region ();
1201 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
1205 if (ar->n_channels() > 1) {
1206 have_multichannel_audio = true;
1210 if (boost::dynamic_pointer_cast<MidiRegion> (r)) {
1214 if (r->is_compound()) {
1215 have_compound_regions = true;
1221 have_unlocked = true;
1224 if (r->video_locked()) {
1225 have_video_locked = true;
1227 have_video_unlocked = true;
1230 if (r->position_lock_style() == MusicTime) {
1231 have_position_lock_style_music = true;
1233 have_position_lock_style_audio = true;
1239 have_unmuted = true;
1245 have_non_opaque = true;
1248 if (!r->at_natural_position()) {
1249 have_not_at_natural_position = true;
1252 if (r->has_transients ()){
1253 have_transients = true;
1257 if (ar->envelope_active()) {
1258 have_envelope_active = true;
1260 have_envelope_inactive = true;
1263 if (ar->scale_amplitude() != 1) {
1264 have_non_unity_scale_amplitude = true;
1267 if (ar->fade_in_active ()) {
1268 have_active_fade_in = true;
1270 have_inactive_fade_in = true;
1273 if (ar->fade_out_active ()) {
1274 have_active_fade_out = true;
1276 have_inactive_fade_out = true;
1281 _region_actions->get_action("split-region-at-transients")->set_sensitive (have_transients);
1283 if (rs.size() > 1) {
1284 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1285 _region_actions->get_action("show-region-properties")->set_sensitive (false);
1286 _region_actions->get_action("rename-region")->set_sensitive (false);
1288 /* XXX need to check whether there is than 1 per
1289 playlist, because otherwise this makes no sense.
1291 _region_actions->get_action("combine-regions")->set_sensitive (true);
1293 _region_actions->get_action("combine-regions")->set_sensitive (false);
1295 } else if (rs.size() == 1) {
1296 _region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
1297 _region_actions->get_action("close-region-gaps")->set_sensitive (false);
1298 _region_actions->get_action("combine-regions")->set_sensitive (false);
1301 if (!have_multichannel_audio) {
1302 _region_actions->get_action("split-multichannel-region")->set_sensitive (false);
1306 editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (false);
1307 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1308 _region_actions->get_action("quantize-region")->set_sensitive (false);
1309 _region_actions->get_action("legatize-region")->set_sensitive (false);
1310 _region_actions->get_action("remove-overlap")->set_sensitive (false);
1311 _region_actions->get_action("transform-region")->set_sensitive (false);
1312 _region_actions->get_action("fork-region")->set_sensitive (false);
1313 _region_actions->get_action("insert-patch-change-context")->set_sensitive (false);
1314 _region_actions->get_action("insert-patch-change")->set_sensitive (false);
1315 _region_actions->get_action("transpose-region")->set_sensitive (false);
1317 editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (true);
1318 /* others were already marked sensitive */
1321 /* ok, moving along... */
1323 if (have_compound_regions) {
1324 _region_actions->get_action("uncombine-regions")->set_sensitive (true);
1326 _region_actions->get_action("uncombine-regions")->set_sensitive (false);
1331 if (have_envelope_active && !have_envelope_inactive) {
1332 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active ();
1333 } else if (have_envelope_active && have_envelope_inactive) {
1334 // Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_inconsistent ();
1339 _region_actions->get_action("loudness-analyze-region")->set_sensitive (false);
1340 _region_actions->get_action("spectral-analyze-region")->set_sensitive (false);
1341 _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
1342 _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
1343 _region_actions->get_action("pitch-shift-region")->set_sensitive (false);
1344 _region_actions->get_action("strip-region-silence")->set_sensitive (false);
1345 _region_actions->get_action("show-rhythm-ferret")->set_sensitive (false);
1349 if (!have_non_unity_scale_amplitude || !have_audio) {
1350 _region_actions->get_action("reset-region-scale-amplitude")->set_sensitive (false);
1353 Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"));
1354 a->set_active (have_locked && !have_unlocked);
1355 if (have_locked && have_unlocked) {
1356 // a->set_inconsistent ();
1359 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-video-lock"));
1360 a->set_active (have_video_locked && !have_video_unlocked);
1361 if (have_video_locked && have_video_unlocked) {
1362 // a->set_inconsistent ();
1365 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
1366 a->set_active (have_position_lock_style_music && !have_position_lock_style_audio);
1368 vector<Widget*> proxies = a->get_proxies();
1369 for (vector<Widget*>::iterator p = proxies.begin(); p != proxies.end(); ++p) {
1370 Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (*p);
1372 cmi->set_inconsistent (have_position_lock_style_music && have_position_lock_style_audio);
1376 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"));
1377 a->set_active (have_muted && !have_unmuted);
1378 if (have_muted && have_unmuted) {
1379 // a->set_inconsistent ();
1382 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"));
1383 a->set_active (have_opaque && !have_non_opaque);
1384 if (have_opaque && have_non_opaque) {
1385 // a->set_inconsistent ();
1388 if (!have_not_at_natural_position) {
1389 _region_actions->get_action("naturalize-region")->set_sensitive (false);
1392 /* XXX: should also check that there is a track of the appropriate type for the selected region */
1393 if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
1394 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (false);
1396 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (true);
1399 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-in"));
1400 a->set_active (have_active_fade_in && !have_inactive_fade_in);
1401 if (have_active_fade_in && have_inactive_fade_in) {
1402 // a->set_inconsistent ();
1405 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-out"));
1406 a->set_active (have_active_fade_out && !have_inactive_fade_out);
1408 if (have_active_fade_out && have_inactive_fade_out) {
1409 // a->set_inconsistent ();
1412 bool const have_active_fade = have_active_fade_in || have_active_fade_out;
1413 bool const have_inactive_fade = have_inactive_fade_in || have_inactive_fade_out;
1415 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fades"));
1416 a->set_active (have_active_fade && !have_inactive_fade);
1418 if (have_active_fade && have_inactive_fade) {
1419 // a->set_inconsistent ();
1422 _ignore_region_action = false;
1424 _all_region_actions_sensitized = false;
1428 Editor::region_selection_changed ()
1430 _regions->block_change_connection (true);
1431 editor_regions_selection_changed_connection.block(true);
1433 if (_region_selection_change_updates_region_list) {
1434 _regions->unselect_all ();
1437 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1438 (*i)->set_selected_regionviews (selection->regions);
1441 if (_region_selection_change_updates_region_list) {
1442 _regions->set_selected (selection->regions);
1445 _regions->block_change_connection (false);
1446 editor_regions_selection_changed_connection.block(false);
1448 sensitize_the_right_region_actions (false);
1450 /* propagate into backend */
1453 if (!selection->regions.empty()) {
1454 _session->set_object_selection (selection->regions.start(), selection->regions.end_frame());
1456 _session->clear_object_selection ();
1463 Editor::point_selection_changed ()
1465 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1466 (*i)->set_selected_points (selection->points);
1471 Editor::select_all_in_track (Selection::Operation op)
1473 list<Selectable *> touched;
1475 if (!clicked_routeview) {
1479 begin_reversible_selection_op (X_("Select All in Track"));
1481 clicked_routeview->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1484 case Selection::Toggle:
1485 selection->add (touched);
1487 case Selection::Set:
1488 selection->set (touched);
1490 case Selection::Extend:
1491 /* meaningless, because we're selecting everything */
1493 case Selection::Add:
1494 selection->add (touched);
1498 commit_reversible_selection_op ();
1502 Editor::select_all_internal_edit (Selection::Operation)
1504 bool selected = false;
1506 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1507 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1509 mrv->select_all_notes ();
1514 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(entered_regionview);
1516 mrv->select_all_notes ();
1524 Editor::select_all_objects (Selection::Operation op)
1526 list<Selectable *> touched;
1528 TrackViewList ts = track_views;
1530 if (internal_editing() && select_all_internal_edit(op)) {
1531 return; // Selected notes
1534 for (TrackViewList::iterator iter = ts.begin(); iter != ts.end(); ++iter) {
1535 if ((*iter)->hidden()) {
1538 (*iter)->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1539 selection->add (*iter);
1543 begin_reversible_selection_op (X_("select all"));
1545 case Selection::Add:
1546 selection->add (touched);
1548 case Selection::Toggle:
1549 selection->add (touched);
1551 case Selection::Set:
1552 selection->set (touched);
1554 case Selection::Extend:
1555 /* meaningless, because we're selecting everything */
1558 commit_reversible_selection_op ();
1562 Editor::invert_selection_in_track ()
1564 list<Selectable *> touched;
1566 if (!clicked_routeview) {
1570 begin_reversible_selection_op (X_("Invert Selection in Track"));
1571 clicked_routeview->get_inverted_selectables (*selection, touched);
1572 selection->set (touched);
1573 commit_reversible_selection_op ();
1577 Editor::invert_selection ()
1579 list<Selectable *> touched;
1581 if (internal_editing()) {
1582 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1583 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1585 mrv->invert_selection ();
1591 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1592 if ((*iter)->hidden()) {
1595 (*iter)->get_inverted_selectables (*selection, touched);
1598 begin_reversible_selection_op (X_("Invert Selection"));
1599 selection->set (touched);
1600 commit_reversible_selection_op ();
1603 /** @param start Start time in session frames.
1604 * @param end End time in session frames.
1605 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
1606 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
1607 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
1608 * within the region are already selected.
1611 Editor::select_all_within (framepos_t start, framepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected)
1613 list<Selectable*> found;
1615 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1617 if ((*iter)->hidden()) {
1621 (*iter)->get_selectables (start, end, top, bot, found);
1624 if (found.empty()) {
1625 selection->clear_objects();
1626 selection->clear_time ();
1630 if (preserve_if_selected && op != Selection::Toggle) {
1631 list<Selectable*>::iterator i = found.begin();
1632 while (i != found.end() && (*i)->selected()) {
1636 if (i == found.end()) {
1641 begin_reversible_selection_op (X_("select all within"));
1643 case Selection::Add:
1644 selection->add (found);
1646 case Selection::Toggle:
1647 selection->toggle (found);
1649 case Selection::Set:
1650 selection->set (found);
1652 case Selection::Extend:
1653 /* not defined yet */
1657 commit_reversible_selection_op ();
1661 Editor::set_selection_from_region ()
1663 if (selection->regions.empty()) {
1667 /* find all the tracks that have selected regions */
1669 set<TimeAxisView*> tracks;
1671 for (RegionSelection::const_iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
1672 tracks.insert (&(*r)->get_time_axis_view());
1676 tvl.insert (tvl.end(), tracks.begin(), tracks.end());
1678 /* select range (this will clear the region selection) */
1680 selection->set (selection->regions.start(), selection->regions.end_frame());
1682 /* and select the tracks */
1684 selection->set (tvl);
1686 set_mouse_mode (Editing::MouseRange, false);
1690 Editor::set_selection_from_punch()
1694 if ((location = _session->locations()->auto_punch_location()) == 0) {
1698 set_selection_from_range (*location);
1702 Editor::set_selection_from_loop()
1706 if ((location = _session->locations()->auto_loop_location()) == 0) {
1709 set_selection_from_range (*location);
1713 Editor::set_selection_from_range (Location& loc)
1715 begin_reversible_selection_op (X_("set selection from range"));
1716 selection->set (loc.start(), loc.end());
1717 commit_reversible_selection_op ();
1719 set_mouse_mode (Editing::MouseRange, false);
1723 Editor::select_all_selectables_using_time_selection ()
1725 list<Selectable *> touched;
1727 if (selection->time.empty()) {
1731 framepos_t start = selection->time[clicked_selection].start;
1732 framepos_t end = selection->time[clicked_selection].end;
1734 if (end - start < 1) {
1740 if (selection->tracks.empty()) {
1743 ts = &selection->tracks;
1746 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1747 if ((*iter)->hidden()) {
1750 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1753 begin_reversible_selection_op (X_("select all from range"));
1754 selection->set (touched);
1755 commit_reversible_selection_op ();
1760 Editor::select_all_selectables_using_punch()
1762 Location* location = _session->locations()->auto_punch_location();
1763 list<Selectable *> touched;
1765 if (location == 0 || (location->end() - location->start() <= 1)) {
1772 if (selection->tracks.empty()) {
1775 ts = &selection->tracks;
1778 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1779 if ((*iter)->hidden()) {
1782 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1784 begin_reversible_selection_op (X_("select all from punch"));
1785 selection->set (touched);
1786 commit_reversible_selection_op ();
1791 Editor::select_all_selectables_using_loop()
1793 Location* location = _session->locations()->auto_loop_location();
1794 list<Selectable *> touched;
1796 if (location == 0 || (location->end() - location->start() <= 1)) {
1803 if (selection->tracks.empty()) {
1806 ts = &selection->tracks;
1809 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1810 if ((*iter)->hidden()) {
1813 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1815 begin_reversible_selection_op (X_("select all from loop"));
1816 selection->set (touched);
1817 commit_reversible_selection_op ();
1822 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1826 list<Selectable *> touched;
1829 start = cursor->current_frame();
1830 end = _session->current_end_frame();
1832 if (cursor->current_frame() > 0) {
1834 end = cursor->current_frame() - 1;
1840 if (internal_editing()) {
1841 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1842 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1844 mrv->select_range (start, end);
1851 begin_reversible_selection_op (X_("select all after cursor"));
1853 begin_reversible_selection_op (X_("select all before cursor"));
1858 if (selection->tracks.empty()) {
1861 ts = &selection->tracks;
1864 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1865 if ((*iter)->hidden()) {
1868 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1870 selection->set (touched);
1871 commit_reversible_selection_op ();
1875 Editor::select_all_selectables_using_edit (bool after, bool from_context_menu)
1879 list<Selectable *> touched;
1882 start = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu);
1883 end = _session->current_end_frame();
1885 if ((end = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu)) > 1) {
1893 if (internal_editing()) {
1894 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1895 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1896 mrv->select_range (start, end);
1902 begin_reversible_selection_op (X_("select all after edit"));
1904 begin_reversible_selection_op (X_("select all before edit"));
1909 if (selection->tracks.empty()) {
1912 ts = &selection->tracks;
1915 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1916 if ((*iter)->hidden()) {
1919 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1921 selection->set (touched);
1922 commit_reversible_selection_op ();
1926 Editor::select_all_selectables_between (bool within)
1930 list<Selectable *> touched;
1932 if (!get_edit_op_range (start, end)) {
1936 if (internal_editing()) {
1937 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1938 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1939 mrv->select_range (start, end);
1946 if (selection->tracks.empty()) {
1949 ts = &selection->tracks;
1952 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1953 if ((*iter)->hidden()) {
1956 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched, within);
1959 begin_reversible_selection_op (X_("Select all Selectables Between"));
1960 selection->set (touched);
1961 commit_reversible_selection_op ();
1965 Editor::select_range_between ()
1970 if ( !selection->time.empty() ) {
1971 selection->clear_time ();
1974 if (!get_edit_op_range (start, end)) {
1978 begin_reversible_selection_op (X_("Select Range Between"));
1979 set_mouse_mode (MouseRange);
1980 selection->set (start, end);
1981 commit_reversible_selection_op ();
1985 Editor::get_edit_op_range (framepos_t& start, framepos_t& end) const
1990 /* if an explicit range exists, use it */
1992 if ( (mouse_mode == MouseRange || get_smart_mode() ) && !selection->time.empty()) {
1993 /* we know that these are ordered */
1994 start = selection->time.start();
1995 end = selection->time.end_frame();
2003 // if (!mouse_frame (m, ignored)) {
2004 // /* mouse is not in a canvas, try playhead+selected marker.
2005 // this is probably most true when using menus.
2008 // if (selection->markers.empty()) {
2012 // start = selection->markers.front()->position();
2013 // end = _session->audible_frame();
2017 // switch (_edit_point) {
2018 // case EditAtPlayhead:
2019 // if (selection->markers.empty()) {
2020 // /* use mouse + playhead */
2022 // end = _session->audible_frame();
2024 // /* use playhead + selected marker */
2025 // start = _session->audible_frame();
2026 // end = selection->markers.front()->position();
2030 // case EditAtMouse:
2031 // /* use mouse + selected marker */
2032 // if (selection->markers.empty()) {
2034 // end = _session->audible_frame();
2036 // start = selection->markers.front()->position();
2041 // case EditAtSelectedMarker:
2042 // /* use mouse + selected marker */
2043 // if (selection->markers.empty()) {
2045 // MessageDialog win (_("No edit range defined"),
2050 // win.set_secondary_text (
2051 // _("the edit point is Selected Marker\nbut there is no selected marker."));
2054 // win.set_default_response (RESPONSE_CLOSE);
2055 // win.set_position (Gtk::WIN_POS_MOUSE);
2060 // return false; // NO RANGE
2062 // start = selection->markers.front()->position();
2068 // if (start == end) {
2072 // if (start > end) {
2073 // swap (start, end);
2076 /* turn range into one delimited by start...end,
2086 Editor::deselect_all ()
2088 begin_reversible_selection_op (X_("Deselect All"));
2089 selection->clear ();
2090 commit_reversible_selection_op ();
2094 Editor::select_range (framepos_t s, framepos_t e)
2096 begin_reversible_selection_op (X_("Select Range"));
2097 selection->add (clicked_axisview);
2098 selection->time.clear ();
2099 long ret = selection->set (s, e);
2100 commit_reversible_selection_op ();