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 if (!selection->selected (&view)) {
93 to_be_added.push_back (&view);
96 /* figure out if we should go forward or backwards */
98 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
101 passed_clicked = true;
104 if (selection->selected (*i)) {
105 if (passed_clicked) {
114 passed_clicked = false;
118 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
121 passed_clicked = true;
125 if (passed_clicked) {
126 if ((*i)->hidden()) {
129 if (selection->selected (*i)) {
131 } else if (!(*i)->hidden()) {
132 to_be_added.push_back (*i);
139 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
142 passed_clicked = true;
146 if (passed_clicked) {
148 if ((*r)->hidden()) {
152 if (selection->selected (*r)) {
154 } else if (!(*r)->hidden()) {
155 to_be_added.push_back (*r);
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);
898 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
900 vector<RegionView*> all_equivalent_regions;
902 get_regions_corresponding_to (region, all_equivalent_regions, region->whole_file());
904 if (all_equivalent_regions.empty()) {
908 begin_reversible_selection_op (X_("set selected regions"));
911 case Selection::Toggle:
912 /* XXX this is not correct */
913 selection->toggle (all_equivalent_regions);
916 selection->set (all_equivalent_regions);
918 case Selection::Extend:
919 selection->add (all_equivalent_regions);
922 selection->add (all_equivalent_regions);
926 commit_reversible_selection_op () ;
930 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
933 boost::shared_ptr<Region> r (weak_r.lock());
939 if ((rv = sv->find_view (r)) == 0) {
943 /* don't reset the selection if its something other than
944 a single other region.
947 if (selection->regions.size() > 1) {
951 begin_reversible_selection_op (X_("set selected regions"));
955 commit_reversible_selection_op () ;
961 Editor::track_selection_changed ()
963 switch (selection->tracks.size()) {
967 /* last element in selection list is the most recently
968 * selected, because we always append to that list.
970 set_selected_mixer_strip (*(selection->tracks.back()));
971 if (!_track_selection_change_without_scroll) {
972 ensure_time_axis_view_is_visible (*(selection->tracks.back()), false);
977 RouteNotificationListPtr routes (new RouteNotificationList);
978 StripableNotificationListPtr stripables (new StripableNotificationList);
980 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
982 bool yn = (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end());
984 (*i)->set_selected (yn);
986 TimeAxisView::Children c = (*i)->get_child_list ();
987 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
988 (*j)->set_selected (find (selection->tracks.begin(), selection->tracks.end(), j->get()) != selection->tracks.end());
992 (*i)->reshow_selection (selection->time);
994 (*i)->hide_selection ();
999 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*i);
1001 routes->push_back (rtav->route());
1002 stripables->push_back (rtav->route());
1007 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
1009 sensitize_the_right_region_actions (false);
1011 /* notify control protocols */
1013 ControlProtocol::StripableSelectionChanged (stripables);
1015 if (sfbrowser && _session && !_session->deletion_in_progress()) {
1016 uint32_t audio_track_cnt = 0;
1017 uint32_t midi_track_cnt = 0;
1019 for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
1020 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*x);
1023 if (atv->is_audio_track()) {
1028 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(*x);
1031 if (mtv->is_midi_track()) {
1038 sfbrowser->reset (audio_track_cnt, midi_track_cnt);
1043 Editor::time_selection_changed ()
1045 /* XXX this is superficially inefficient. Hide the selection in all
1046 * tracks, then show it in all selected tracks.
1048 * However, if you investigate what this actually does, it isn't
1049 * anywhere nearly as bad as it may appear. Remember: nothing is
1050 * redrawn or even recomputed during these two loops - that only
1051 * happens when we next render ...
1054 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1055 (*i)->hide_selection ();
1058 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1059 (*i)->show_selection (selection->time);
1062 if (selection->time.empty()) {
1063 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
1065 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
1068 /* propagate into backend, but only when there is no drag or we are at
1069 * the end of a drag, otherwise this is too expensive (could case a
1070 * locate per mouse motion event.
1073 if (_session && !_drags->active()) {
1074 if (selection->time.length() != 0) {
1075 _session->set_range_selection (selection->time.start(), selection->time.end_frame());
1077 _session->clear_range_selection ();
1082 /** Set all region actions to have a given sensitivity */
1084 Editor::sensitize_all_region_actions (bool s)
1086 Glib::ListHandle<Glib::RefPtr<Action> > all = _region_actions->get_actions ();
1088 for (Glib::ListHandle<Glib::RefPtr<Action> >::iterator i = all.begin(); i != all.end(); ++i) {
1089 (*i)->set_sensitive (s);
1092 _all_region_actions_sensitized = s;
1095 /** Sensitize region-based actions.
1097 * This method is called from whenever we leave the canvas, either by moving
1098 * the pointer out of it, or by popping up a context menu. See
1099 * Editor::{entered,left}_track_canvas() for details there.
1102 Editor::sensitize_the_right_region_actions (bool because_canvas_crossing)
1104 bool have_selection = false;
1105 bool have_entered = false;
1106 bool have_edit_point = false;
1109 // std::cerr << "STRRA: crossing ? " << because_canvas_crossing << " within ? " << within_track_canvas
1112 if (!selection->regions.empty()) {
1113 have_selection = true;
1114 rs = selection->regions;
1117 if (entered_regionview) {
1118 have_entered = true;
1119 rs.add (entered_regionview);
1122 if (rs.empty() && !selection->tracks.empty()) {
1124 /* no selected regions, but some selected tracks.
1127 if (_edit_point == EditAtMouse) {
1128 if (!within_track_canvas) {
1129 /* pointer is not in canvas, so edit point is meaningless */
1130 have_edit_point = false;
1132 /* inside canvas. we don't know where the edit
1133 point will be when an action is invoked, but
1134 assume it could intersect with a region.
1136 have_edit_point = true;
1139 RegionSelection at_edit_point;
1140 framepos_t const where = get_preferred_edit_position (Editing::EDIT_IGNORE_NONE, false, !within_track_canvas);
1141 get_regions_at (at_edit_point, where, selection->tracks);
1142 if (!at_edit_point.empty()) {
1143 have_edit_point = true;
1146 rs.insert (rs.end(), at_edit_point.begin(), at_edit_point.end());
1151 //std::cerr << "\tfinal have selection: " << have_selection
1152 // << " have entered " << have_entered
1153 // << " have edit point " << have_edit_point
1154 // << " EP = " << enum_2_string (_edit_point)
1157 typedef std::map<std::string,RegionAction> RegionActionMap;
1159 _ignore_region_action = true;
1161 for (RegionActionMap::iterator x = region_action_map.begin(); x != region_action_map.end(); ++x) {
1162 RegionActionTarget tgt = x->second.target;
1163 bool sensitive = false;
1165 if ((tgt & SelectedRegions) && have_selection) {
1167 } else if ((tgt & EnteredRegions) && have_entered) {
1169 } else if ((tgt & EditPointRegions) && have_edit_point) {
1173 x->second.action->set_sensitive (sensitive);
1176 /* Look through the regions that are selected and make notes about what we have got */
1178 bool have_audio = false;
1179 bool have_multichannel_audio = false;
1180 bool have_midi = false;
1181 bool have_locked = false;
1182 bool have_unlocked = false;
1183 bool have_video_locked = false;
1184 bool have_video_unlocked = false;
1185 bool have_position_lock_style_audio = false;
1186 bool have_position_lock_style_music = false;
1187 bool have_muted = false;
1188 bool have_unmuted = false;
1189 bool have_opaque = false;
1190 bool have_non_opaque = false;
1191 bool have_not_at_natural_position = false;
1192 bool have_envelope_active = false;
1193 bool have_envelope_inactive = false;
1194 bool have_non_unity_scale_amplitude = false;
1195 bool have_compound_regions = false;
1196 bool have_inactive_fade_in = false;
1197 bool have_inactive_fade_out = false;
1198 bool have_active_fade_in = false;
1199 bool have_active_fade_out = false;
1200 bool have_transients = false;
1202 for (list<RegionView*>::const_iterator i = rs.begin(); i != rs.end(); ++i) {
1204 boost::shared_ptr<Region> r = (*i)->region ();
1205 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
1209 if (ar->n_channels() > 1) {
1210 have_multichannel_audio = true;
1214 if (boost::dynamic_pointer_cast<MidiRegion> (r)) {
1218 if (r->is_compound()) {
1219 have_compound_regions = true;
1225 have_unlocked = true;
1228 if (r->video_locked()) {
1229 have_video_locked = true;
1231 have_video_unlocked = true;
1234 if (r->position_lock_style() == MusicTime) {
1235 have_position_lock_style_music = true;
1237 have_position_lock_style_audio = true;
1243 have_unmuted = true;
1249 have_non_opaque = true;
1252 if (!r->at_natural_position()) {
1253 have_not_at_natural_position = true;
1256 if (r->has_transients ()){
1257 have_transients = true;
1261 if (ar->envelope_active()) {
1262 have_envelope_active = true;
1264 have_envelope_inactive = true;
1267 if (ar->scale_amplitude() != 1) {
1268 have_non_unity_scale_amplitude = true;
1271 if (ar->fade_in_active ()) {
1272 have_active_fade_in = true;
1274 have_inactive_fade_in = true;
1277 if (ar->fade_out_active ()) {
1278 have_active_fade_out = true;
1280 have_inactive_fade_out = true;
1285 _region_actions->get_action("split-region-at-transients")->set_sensitive (have_transients);
1287 if (rs.size() > 1) {
1288 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1289 _region_actions->get_action("show-region-properties")->set_sensitive (false);
1290 _region_actions->get_action("rename-region")->set_sensitive (false);
1292 /* XXX need to check whether there is than 1 per
1293 playlist, because otherwise this makes no sense.
1295 _region_actions->get_action("combine-regions")->set_sensitive (true);
1297 _region_actions->get_action("combine-regions")->set_sensitive (false);
1299 } else if (rs.size() == 1) {
1300 _region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
1301 _region_actions->get_action("close-region-gaps")->set_sensitive (false);
1302 _region_actions->get_action("combine-regions")->set_sensitive (false);
1305 if (!have_multichannel_audio) {
1306 _region_actions->get_action("split-multichannel-region")->set_sensitive (false);
1310 editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (false);
1311 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1312 _region_actions->get_action("quantize-region")->set_sensitive (false);
1313 _region_actions->get_action("legatize-region")->set_sensitive (false);
1314 _region_actions->get_action("remove-overlap")->set_sensitive (false);
1315 _region_actions->get_action("transform-region")->set_sensitive (false);
1316 _region_actions->get_action("fork-region")->set_sensitive (false);
1317 _region_actions->get_action("insert-patch-change-context")->set_sensitive (false);
1318 _region_actions->get_action("insert-patch-change")->set_sensitive (false);
1319 _region_actions->get_action("transpose-region")->set_sensitive (false);
1321 editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (true);
1322 /* others were already marked sensitive */
1325 /* ok, moving along... */
1327 if (have_compound_regions) {
1328 _region_actions->get_action("uncombine-regions")->set_sensitive (true);
1330 _region_actions->get_action("uncombine-regions")->set_sensitive (false);
1335 if (have_envelope_active && !have_envelope_inactive) {
1336 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active ();
1337 } else if (have_envelope_active && have_envelope_inactive) {
1338 // Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_inconsistent ();
1343 _region_actions->get_action("loudness-analyze-region")->set_sensitive (false);
1344 _region_actions->get_action("spectral-analyze-region")->set_sensitive (false);
1345 _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
1346 _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
1347 _region_actions->get_action("pitch-shift-region")->set_sensitive (false);
1348 _region_actions->get_action("strip-region-silence")->set_sensitive (false);
1349 _region_actions->get_action("show-rhythm-ferret")->set_sensitive (false);
1353 if (!have_non_unity_scale_amplitude || !have_audio) {
1354 _region_actions->get_action("reset-region-scale-amplitude")->set_sensitive (false);
1357 Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"));
1358 a->set_active (have_locked && !have_unlocked);
1359 if (have_locked && have_unlocked) {
1360 // a->set_inconsistent ();
1363 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-video-lock"));
1364 a->set_active (have_video_locked && !have_video_unlocked);
1365 if (have_video_locked && have_video_unlocked) {
1366 // a->set_inconsistent ();
1369 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
1370 a->set_active (have_position_lock_style_music && !have_position_lock_style_audio);
1372 vector<Widget*> proxies = a->get_proxies();
1373 for (vector<Widget*>::iterator p = proxies.begin(); p != proxies.end(); ++p) {
1374 Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (*p);
1376 cmi->set_inconsistent (have_position_lock_style_music && have_position_lock_style_audio);
1380 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"));
1381 a->set_active (have_muted && !have_unmuted);
1382 if (have_muted && have_unmuted) {
1383 // a->set_inconsistent ();
1386 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"));
1387 a->set_active (have_opaque && !have_non_opaque);
1388 if (have_opaque && have_non_opaque) {
1389 // a->set_inconsistent ();
1392 if (!have_not_at_natural_position) {
1393 _region_actions->get_action("naturalize-region")->set_sensitive (false);
1396 /* XXX: should also check that there is a track of the appropriate type for the selected region */
1397 if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
1398 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (false);
1400 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (true);
1403 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-in"));
1404 a->set_active (have_active_fade_in && !have_inactive_fade_in);
1405 if (have_active_fade_in && have_inactive_fade_in) {
1406 // a->set_inconsistent ();
1409 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-out"));
1410 a->set_active (have_active_fade_out && !have_inactive_fade_out);
1412 if (have_active_fade_out && have_inactive_fade_out) {
1413 // a->set_inconsistent ();
1416 bool const have_active_fade = have_active_fade_in || have_active_fade_out;
1417 bool const have_inactive_fade = have_inactive_fade_in || have_inactive_fade_out;
1419 a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fades"));
1420 a->set_active (have_active_fade && !have_inactive_fade);
1422 if (have_active_fade && have_inactive_fade) {
1423 // a->set_inconsistent ();
1426 _ignore_region_action = false;
1428 _all_region_actions_sensitized = false;
1432 Editor::region_selection_changed ()
1434 _regions->block_change_connection (true);
1435 editor_regions_selection_changed_connection.block(true);
1437 if (_region_selection_change_updates_region_list) {
1438 _regions->unselect_all ();
1441 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1442 (*i)->set_selected_regionviews (selection->regions);
1445 if (_region_selection_change_updates_region_list) {
1446 _regions->set_selected (selection->regions);
1449 _regions->block_change_connection (false);
1450 editor_regions_selection_changed_connection.block(false);
1452 sensitize_the_right_region_actions (false);
1454 /* propagate into backend */
1457 if (!selection->regions.empty()) {
1458 _session->set_object_selection (selection->regions.start(), selection->regions.end_frame());
1460 _session->clear_object_selection ();
1467 Editor::point_selection_changed ()
1469 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1470 (*i)->set_selected_points (selection->points);
1475 Editor::select_all_in_track (Selection::Operation op)
1477 list<Selectable *> touched;
1479 if (!clicked_routeview) {
1483 begin_reversible_selection_op (X_("Select All in Track"));
1485 clicked_routeview->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1488 case Selection::Toggle:
1489 selection->add (touched);
1491 case Selection::Set:
1492 selection->set (touched);
1494 case Selection::Extend:
1495 /* meaningless, because we're selecting everything */
1497 case Selection::Add:
1498 selection->add (touched);
1502 commit_reversible_selection_op ();
1506 Editor::select_all_internal_edit (Selection::Operation)
1508 bool selected = false;
1510 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1511 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1513 mrv->select_all_notes ();
1518 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(entered_regionview);
1520 mrv->select_all_notes ();
1528 Editor::select_all_objects (Selection::Operation op)
1530 list<Selectable *> touched;
1532 TrackViewList ts = track_views;
1534 if (internal_editing() && select_all_internal_edit(op)) {
1535 return; // Selected notes
1538 for (TrackViewList::iterator iter = ts.begin(); iter != ts.end(); ++iter) {
1539 if ((*iter)->hidden()) {
1542 (*iter)->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1543 selection->add (*iter);
1547 begin_reversible_selection_op (X_("select all"));
1549 case Selection::Add:
1550 selection->add (touched);
1552 case Selection::Toggle:
1553 selection->add (touched);
1555 case Selection::Set:
1556 selection->set (touched);
1558 case Selection::Extend:
1559 /* meaningless, because we're selecting everything */
1562 commit_reversible_selection_op ();
1566 Editor::invert_selection_in_track ()
1568 list<Selectable *> touched;
1570 if (!clicked_routeview) {
1574 begin_reversible_selection_op (X_("Invert Selection in Track"));
1575 clicked_routeview->get_inverted_selectables (*selection, touched);
1576 selection->set (touched);
1577 commit_reversible_selection_op ();
1581 Editor::invert_selection ()
1583 list<Selectable *> touched;
1585 if (internal_editing()) {
1586 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1587 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1589 mrv->invert_selection ();
1595 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1596 if ((*iter)->hidden()) {
1599 (*iter)->get_inverted_selectables (*selection, touched);
1602 begin_reversible_selection_op (X_("Invert Selection"));
1603 selection->set (touched);
1604 commit_reversible_selection_op ();
1607 /** @param start Start time in session frames.
1608 * @param end End time in session frames.
1609 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
1610 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
1611 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
1612 * within the region are already selected.
1615 Editor::select_all_within (framepos_t start, framepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected)
1617 list<Selectable*> found;
1619 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1621 if ((*iter)->hidden()) {
1625 (*iter)->get_selectables (start, end, top, bot, found);
1628 if (found.empty()) {
1629 selection->clear_objects();
1630 selection->clear_time ();
1634 if (preserve_if_selected && op != Selection::Toggle) {
1635 list<Selectable*>::iterator i = found.begin();
1636 while (i != found.end() && (*i)->selected()) {
1640 if (i == found.end()) {
1645 begin_reversible_selection_op (X_("select all within"));
1647 case Selection::Add:
1648 selection->add (found);
1650 case Selection::Toggle:
1651 selection->toggle (found);
1653 case Selection::Set:
1654 selection->set (found);
1656 case Selection::Extend:
1657 /* not defined yet */
1661 commit_reversible_selection_op ();
1665 Editor::set_selection_from_region ()
1667 if (selection->regions.empty()) {
1671 /* find all the tracks that have selected regions */
1673 set<TimeAxisView*> tracks;
1675 for (RegionSelection::const_iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
1676 tracks.insert (&(*r)->get_time_axis_view());
1680 tvl.insert (tvl.end(), tracks.begin(), tracks.end());
1682 /* select range (this will clear the region selection) */
1684 selection->set (selection->regions.start(), selection->regions.end_frame());
1686 /* and select the tracks */
1688 selection->set (tvl);
1690 set_mouse_mode (Editing::MouseRange, false);
1694 Editor::set_selection_from_punch()
1698 if ((location = _session->locations()->auto_punch_location()) == 0) {
1702 set_selection_from_range (*location);
1706 Editor::set_selection_from_loop()
1710 if ((location = _session->locations()->auto_loop_location()) == 0) {
1713 set_selection_from_range (*location);
1717 Editor::set_selection_from_range (Location& loc)
1719 begin_reversible_selection_op (X_("set selection from range"));
1720 selection->set (loc.start(), loc.end());
1721 commit_reversible_selection_op ();
1723 set_mouse_mode (Editing::MouseRange, false);
1727 Editor::select_all_selectables_using_time_selection ()
1729 list<Selectable *> touched;
1731 if (selection->time.empty()) {
1735 framepos_t start = selection->time[clicked_selection].start;
1736 framepos_t end = selection->time[clicked_selection].end;
1738 if (end - start < 1) {
1744 if (selection->tracks.empty()) {
1747 ts = &selection->tracks;
1750 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1751 if ((*iter)->hidden()) {
1754 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1757 begin_reversible_selection_op (X_("select all from range"));
1758 selection->set (touched);
1759 commit_reversible_selection_op ();
1764 Editor::select_all_selectables_using_punch()
1766 Location* location = _session->locations()->auto_punch_location();
1767 list<Selectable *> touched;
1769 if (location == 0 || (location->end() - location->start() <= 1)) {
1776 if (selection->tracks.empty()) {
1779 ts = &selection->tracks;
1782 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1783 if ((*iter)->hidden()) {
1786 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1788 begin_reversible_selection_op (X_("select all from punch"));
1789 selection->set (touched);
1790 commit_reversible_selection_op ();
1795 Editor::select_all_selectables_using_loop()
1797 Location* location = _session->locations()->auto_loop_location();
1798 list<Selectable *> touched;
1800 if (location == 0 || (location->end() - location->start() <= 1)) {
1807 if (selection->tracks.empty()) {
1810 ts = &selection->tracks;
1813 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1814 if ((*iter)->hidden()) {
1817 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1819 begin_reversible_selection_op (X_("select all from loop"));
1820 selection->set (touched);
1821 commit_reversible_selection_op ();
1826 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1830 list<Selectable *> touched;
1833 start = cursor->current_frame();
1834 end = _session->current_end_frame();
1836 if (cursor->current_frame() > 0) {
1838 end = cursor->current_frame() - 1;
1844 if (internal_editing()) {
1845 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1846 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1848 mrv->select_range (start, end);
1855 begin_reversible_selection_op (X_("select all after cursor"));
1857 begin_reversible_selection_op (X_("select all before cursor"));
1862 if (selection->tracks.empty()) {
1865 ts = &selection->tracks;
1868 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1869 if ((*iter)->hidden()) {
1872 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1874 selection->set (touched);
1875 commit_reversible_selection_op ();
1879 Editor::select_all_selectables_using_edit (bool after, bool from_context_menu)
1883 list<Selectable *> touched;
1886 start = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu);
1887 end = _session->current_end_frame();
1889 if ((end = get_preferred_edit_position(EDIT_IGNORE_NONE, from_context_menu)) > 1) {
1897 if (internal_editing()) {
1898 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1899 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1900 mrv->select_range (start, end);
1906 begin_reversible_selection_op (X_("select all after edit"));
1908 begin_reversible_selection_op (X_("select all before edit"));
1913 if (selection->tracks.empty()) {
1916 ts = &selection->tracks;
1919 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1920 if ((*iter)->hidden()) {
1923 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1925 selection->set (touched);
1926 commit_reversible_selection_op ();
1930 Editor::select_all_selectables_between (bool within)
1934 list<Selectable *> touched;
1936 if (!get_edit_op_range (start, end)) {
1940 if (internal_editing()) {
1941 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1942 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1943 mrv->select_range (start, end);
1950 if (selection->tracks.empty()) {
1953 ts = &selection->tracks;
1956 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1957 if ((*iter)->hidden()) {
1960 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched, within);
1963 begin_reversible_selection_op (X_("Select all Selectables Between"));
1964 selection->set (touched);
1965 commit_reversible_selection_op ();
1969 Editor::select_range_between ()
1974 if ( !selection->time.empty() ) {
1975 selection->clear_time ();
1978 if (!get_edit_op_range (start, end)) {
1982 begin_reversible_selection_op (X_("Select Range Between"));
1983 set_mouse_mode (MouseRange);
1984 selection->set (start, end);
1985 commit_reversible_selection_op ();
1989 Editor::get_edit_op_range (framepos_t& start, framepos_t& end) const
1994 /* if an explicit range exists, use it */
1996 if ( (mouse_mode == MouseRange || get_smart_mode() ) && !selection->time.empty()) {
1997 /* we know that these are ordered */
1998 start = selection->time.start();
1999 end = selection->time.end_frame();
2007 // if (!mouse_frame (m, ignored)) {
2008 // /* mouse is not in a canvas, try playhead+selected marker.
2009 // this is probably most true when using menus.
2012 // if (selection->markers.empty()) {
2016 // start = selection->markers.front()->position();
2017 // end = _session->audible_frame();
2021 // switch (_edit_point) {
2022 // case EditAtPlayhead:
2023 // if (selection->markers.empty()) {
2024 // /* use mouse + playhead */
2026 // end = _session->audible_frame();
2028 // /* use playhead + selected marker */
2029 // start = _session->audible_frame();
2030 // end = selection->markers.front()->position();
2034 // case EditAtMouse:
2035 // /* use mouse + selected marker */
2036 // if (selection->markers.empty()) {
2038 // end = _session->audible_frame();
2040 // start = selection->markers.front()->position();
2045 // case EditAtSelectedMarker:
2046 // /* use mouse + selected marker */
2047 // if (selection->markers.empty()) {
2049 // MessageDialog win (_("No edit range defined"),
2054 // win.set_secondary_text (
2055 // _("the edit point is Selected Marker\nbut there is no selected marker."));
2058 // win.set_default_response (RESPONSE_CLOSE);
2059 // win.set_position (Gtk::WIN_POS_MOUSE);
2064 // return false; // NO RANGE
2066 // start = selection->markers.front()->position();
2072 // if (start == end) {
2076 // if (start > end) {
2077 // swap (start, end);
2080 /* turn range into one delimited by start...end,
2090 Editor::deselect_all ()
2092 begin_reversible_selection_op (X_("Deselect All"));
2093 selection->clear ();
2094 commit_reversible_selection_op ();
2098 Editor::select_range (framepos_t s, framepos_t e)
2100 begin_reversible_selection_op (X_("Select Range"));
2101 selection->add (clicked_axisview);
2102 selection->time.clear ();
2103 long ret = selection->set (s, e);
2104 commit_reversible_selection_op ();