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/session.h"
26 #include "ardour/playlist.h"
27 #include "ardour/route_group.h"
28 #include "ardour/profile.h"
29 #include "ardour/midi_region.h"
33 #include "audio_time_axis.h"
34 #include "audio_region_view.h"
35 #include "audio_streamview.h"
36 #include "automation_line.h"
37 #include "control_point.h"
38 #include "editor_regions.h"
43 using namespace ARDOUR;
47 using namespace Gtkmm2ext;
48 using namespace Editing;
50 struct TrackViewByPositionSorter
52 bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
53 return a->y_position() < b->y_position();
58 Editor::extend_selection_to_track (TimeAxisView& view)
60 if (selection->selected (&view)) {
61 /* already selected, do nothing */
65 if (selection->tracks.empty()) {
67 if (!selection->selected (&view)) {
68 selection->set (&view);
75 /* something is already selected, so figure out which range of things to add */
77 TrackViewList to_be_added;
78 TrackViewList sorted = track_views;
79 TrackViewByPositionSorter cmp;
80 bool passed_clicked = false;
85 if (!selection->selected (&view)) {
86 to_be_added.push_back (&view);
89 /* figure out if we should go forward or backwards */
91 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
94 passed_clicked = true;
97 if (selection->selected (*i)) {
107 passed_clicked = false;
111 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
114 passed_clicked = true;
118 if (passed_clicked) {
119 if ((*i)->hidden()) {
122 if (selection->selected (*i)) {
124 } else if (!(*i)->hidden()) {
125 to_be_added.push_back (*i);
132 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
135 passed_clicked = true;
139 if (passed_clicked) {
141 if ((*r)->hidden()) {
145 if (selection->selected (*r)) {
147 } else if (!(*r)->hidden()) {
148 to_be_added.push_back (*r);
154 if (!to_be_added.empty()) {
155 selection->add (to_be_added);
163 Editor::select_all_tracks ()
165 TrackViewList visible_views;
166 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
167 if ((*i)->marked_for_display()) {
168 visible_views.push_back (*i);
171 selection->set (visible_views);
174 /** Select clicked_axisview, unless there are no currently selected
175 * tracks, in which case nothing will happen unless `force' is true.
178 Editor::set_selected_track_as_side_effect (Selection::Operation op, bool /*force*/)
180 if (!clicked_axisview) {
185 if (!clicked_routeview) {
189 bool had_tracks = !selection->tracks.empty();
190 RouteGroup* group = clicked_routeview->route()->route_group();
191 RouteGroup& arg (_session->all_route_group());
194 case Selection::Toggle:
195 if (selection->selected (clicked_axisview)) {
196 if (arg.is_select() && arg.is_active()) {
197 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
198 selection->remove(*i);
200 } else 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);
206 selection->remove (clicked_axisview);
209 if (arg.is_select() && arg.is_active()) {
210 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
213 } else if (group && group->is_active()) {
214 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
215 if ( (*i)->route_group() == group)
219 selection->add (clicked_axisview);
225 if (!had_tracks && arg.is_select() && arg.is_active()) {
226 /* nothing was selected already, and all group is active etc. so use
229 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
232 } else if (group && group->is_active()) {
233 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
234 if ((*i)->route_group() == group)
238 selection->add (clicked_axisview);
244 if (!had_tracks && arg.is_select() && arg.is_active()) {
245 /* nothing was selected already, and all group is active etc. so use
248 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
251 } else if (group && group->is_active()) {
252 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
253 if ((*i)->route_group() == group)
257 selection->set (clicked_axisview);
261 case Selection::Extend:
263 cerr << ("Editor::set_selected_track_as_side_effect case Selection::Add not yet implemented\n");
267 #else // the older version
269 if (!selection->tracks.empty()) {
270 if (!selection->selected (clicked_axisview)) {
271 selection->add (clicked_axisview);
275 selection->set (clicked_axisview);
281 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
284 case Selection::Toggle:
285 if (selection->selected (&view)) {
287 selection->remove (&view);
290 selection->add (&view);
295 if (!selection->selected (&view)) {
296 selection->add (&view);
301 selection->set (&view);
304 case Selection::Extend:
305 extend_selection_to_track (view);
311 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
313 if (!clicked_routeview) {
321 set_selected_track (*clicked_routeview, op, no_remove);
325 Editor::set_selected_control_point_from_click (Selection::Operation op, bool /*no_remove*/)
327 if (!clicked_control_point) {
333 selection->set (clicked_control_point);
336 selection->add (clicked_control_point);
338 case Selection::Toggle:
339 selection->toggle (clicked_control_point);
341 case Selection::Extend:
350 Editor::get_onscreen_tracks (TrackViewList& tvl)
352 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
353 if ((*i)->y_position() < _canvas_height) {
359 /** Call a slot for a given `basis' track and also for any track that is in the same
360 * active route group with a particular set of properties.
362 * @param sl Slot to call.
363 * @param basis Basis track.
364 * @param prop Properties that active edit groups must share to be included in the map.
368 Editor::mapover_tracks (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
370 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
372 if (route_basis == 0) {
376 set<RouteTimeAxisView*> tracks;
377 tracks.insert (route_basis);
379 RouteGroup* group = route_basis->route()->route_group();
381 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id) ) {
383 /* the basis is a member of an active route group, with the appropriate
384 properties; find other members */
386 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
387 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
388 if (v && v->route()->route_group() == group) {
395 uint32_t const sz = tracks.size ();
397 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
403 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
405 boost::shared_ptr<Playlist> pl;
406 vector<boost::shared_ptr<Region> > results;
408 boost::shared_ptr<Track> tr;
410 if ((tr = tv.track()) == 0) {
415 if (&tv == &basis->get_time_axis_view()) {
416 /* looking in same track as the original */
420 if ((pl = tr->playlist()) != 0) {
421 pl->get_equivalent_regions (basis->region(), results);
424 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
425 if ((marv = tv.view()->find_view (*ir)) != 0) {
426 all_equivs->push_back (marv);
432 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, PBD::PropertyID property) const
434 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_time_axis_view(), property);
436 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
438 equivalent_regions.push_back (basis);
442 Editor::get_equivalent_regions (RegionSelection & basis, PBD::PropertyID prop) const
444 RegionSelection equivalent;
446 for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
448 vector<RegionView*> eq;
451 sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
452 &(*i)->get_time_axis_view(), prop
455 for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
467 Editor::get_regionview_count_from_region_list (boost::shared_ptr<Region> region)
469 int region_count = 0;
471 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
473 RouteTimeAxisView* tatv;
475 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
477 boost::shared_ptr<Playlist> pl;
478 vector<boost::shared_ptr<Region> > results;
480 boost::shared_ptr<Track> tr;
482 if ((tr = tatv->track()) == 0) {
487 if ((pl = (tr->playlist())) != 0) {
488 pl->get_region_list_equivalent_regions (region, results);
491 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
492 if ((marv = tatv->view()->find_view (*ir)) != 0) {
505 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool /*no_track_remove*/)
507 vector<RegionView*> all_equivalent_regions;
510 if (!clicked_regionview || !clicked_routeview) {
515 button_release_can_deselect = false;
518 if (op == Selection::Toggle || op == Selection::Set) {
522 case Selection::Toggle:
524 if (selection->selected (clicked_regionview)) {
527 /* whatever was clicked was selected already; do nothing here but allow
528 the button release to deselect it
531 button_release_can_deselect = true;
535 if (button_release_can_deselect) {
537 /* just remove this one region, but only on a permitted button release */
539 selection->remove (clicked_regionview);
542 /* no more deselect action on button release till a new press
543 finds an already selected object.
546 button_release_can_deselect = false;
554 if (selection->selected (clicked_routeview)) {
555 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
557 all_equivalent_regions.push_back (clicked_regionview);
560 /* add all the equivalent regions, but only on button press */
562 if (!all_equivalent_regions.empty()) {
566 selection->add (all_equivalent_regions);
572 if (!selection->selected (clicked_regionview)) {
573 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
574 selection->set (all_equivalent_regions);
577 /* no commit necessary: clicked on an already selected region */
587 } else if (op == Selection::Extend) {
589 list<Selectable*> results;
590 framepos_t last_frame;
591 framepos_t first_frame;
592 bool same_track = false;
594 /* 1. find the last selected regionview in the track that was clicked in */
597 first_frame = max_framepos;
599 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
600 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
602 if ((*x)->region()->last_frame() > last_frame) {
603 last_frame = (*x)->region()->last_frame();
606 if ((*x)->region()->first_frame() < first_frame) {
607 first_frame = (*x)->region()->first_frame();
616 /* 2. figure out the boundaries for our search for new objects */
618 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
620 if (last_frame < clicked_regionview->region()->first_frame()) {
621 first_frame = last_frame;
622 last_frame = clicked_regionview->region()->last_frame();
624 last_frame = first_frame;
625 first_frame = clicked_regionview->region()->first_frame();
629 case OverlapExternal:
630 if (last_frame < clicked_regionview->region()->first_frame()) {
631 first_frame = last_frame;
632 last_frame = clicked_regionview->region()->last_frame();
634 last_frame = first_frame;
635 first_frame = clicked_regionview->region()->first_frame();
639 case OverlapInternal:
640 if (last_frame < clicked_regionview->region()->first_frame()) {
641 first_frame = last_frame;
642 last_frame = clicked_regionview->region()->last_frame();
644 last_frame = first_frame;
645 first_frame = clicked_regionview->region()->first_frame();
651 /* nothing to do except add clicked region to selection, since it
652 overlaps with the existing selection in this track.
659 /* click in a track that has no regions selected, so extend vertically
660 to pick out all regions that are defined by the existing selection
665 first_frame = clicked_regionview->region()->position();
666 last_frame = clicked_regionview->region()->last_frame();
668 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
669 if ((*i)->region()->position() < first_frame) {
670 first_frame = (*i)->region()->position();
672 if ((*i)->region()->last_frame() + 1 > last_frame) {
673 last_frame = (*i)->region()->last_frame();
678 /* 2. find all the tracks we should select in */
680 set<RouteTimeAxisView*> relevant_tracks;
682 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
683 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
685 relevant_tracks.insert (r);
689 set<RouteTimeAxisView*> already_in_selection;
691 if (relevant_tracks.empty()) {
693 /* no tracks selected .. thus .. if the
694 regionview we're in isn't selected
695 (i.e. we're about to extend to it), then
696 find all tracks between the this one and
700 if (!selection->selected (clicked_regionview)) {
702 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&clicked_regionview->get_time_axis_view());
706 /* add this track to the ones we will search */
708 relevant_tracks.insert (rtv);
710 /* find the track closest to this one that
711 already a selected region.
714 RouteTimeAxisView* closest = 0;
715 int distance = INT_MAX;
716 int key = rtv->route()->order_key ("editor");
718 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
720 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
722 if (artv && artv != rtv) {
724 pair<set<RouteTimeAxisView*>::iterator,bool> result;
726 result = already_in_selection.insert (artv);
729 /* newly added to already_in_selection */
731 int d = artv->route()->order_key ("editor");
735 if (abs (d) < distance) {
745 /* now add all tracks between that one and this one */
747 int okey = closest->route()->order_key ("editor");
753 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
754 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
755 if (artv && artv != rtv) {
757 int k = artv->route()->order_key ("editor");
759 if (k >= okey && k <= key) {
761 /* in range but don't add it if
762 it already has tracks selected.
763 this avoids odd selection
764 behaviour that feels wrong.
767 if (find (already_in_selection.begin(),
768 already_in_selection.end(),
769 artv) == already_in_selection.end()) {
771 relevant_tracks.insert (artv);
781 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
782 one that was clicked.
785 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
786 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
789 /* 4. convert to a vector of regions */
791 vector<RegionView*> regions;
793 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
796 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
797 regions.push_back (arv);
801 if (!regions.empty()) {
802 selection->add (regions);
813 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
815 vector<RegionView*> all_equivalent_regions;
817 get_regions_corresponding_to (region, all_equivalent_regions);
819 if (all_equivalent_regions.empty()) {
823 begin_reversible_command (_("set selected regions"));
826 case Selection::Toggle:
827 /* XXX this is not correct */
828 selection->toggle (all_equivalent_regions);
831 selection->set (all_equivalent_regions);
833 case Selection::Extend:
834 selection->add (all_equivalent_regions);
837 selection->add (all_equivalent_regions);
841 commit_reversible_command () ;
845 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
848 boost::shared_ptr<Region> r (weak_r.lock());
854 if ((rv = sv->find_view (r)) == 0) {
858 /* don't reset the selection if its something other than
859 a single other region.
862 if (selection->regions.size() > 1) {
866 begin_reversible_command (_("set selected regions"));
870 commit_reversible_command () ;
876 Editor::track_selection_changed ()
878 switch (selection->tracks.size()) {
882 set_selected_mixer_strip (*(selection->tracks.front()));
886 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
888 bool yn = (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end());
890 (*i)->set_selected (yn);
892 TimeAxisView::Children c = (*i)->get_child_list ();
893 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
894 (*j)->set_selected (find (selection->tracks.begin(), selection->tracks.end(), j->get()) != selection->tracks.end());
898 ((mouse_mode == MouseRange) ||
899 ((mouse_mode == MouseObject) && (_join_object_range_state == JOIN_OBJECT_RANGE_OBJECT)))) {
900 (*i)->reshow_selection (selection->time);
902 (*i)->hide_selection ();
906 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
910 Editor::time_selection_changed ()
912 if (Profile->get_sae()) {
916 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
917 (*i)->hide_selection ();
920 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
921 (*i)->show_selection (selection->time);
924 if (selection->time.empty()) {
925 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
927 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
931 /** Set all region actions to have a given sensitivity */
933 Editor::sensitize_all_region_actions (bool s)
935 Glib::ListHandle<Glib::RefPtr<Action> > all = _region_actions->get_actions ();
937 for (Glib::ListHandle<Glib::RefPtr<Action> >::iterator i = all.begin(); i != all.end(); ++i) {
938 (*i)->set_sensitive (s);
941 _all_region_actions_sensitized = s;
944 /** Sensitize region-based actions based on the selection ONLY, ignoring the entered_regionview.
945 * This method should be called just before displaying a Region menu. When a Region menu is not
946 * currently being shown, all region actions are sensitized so that hotkey-triggered actions
947 * on entered_regionviews work without having to check sensitivity every time the selection or
948 * entered_regionview changes.
950 * This method also sets up toggle action state as appropriate.
953 Editor::sensitize_the_right_region_actions ()
955 RegionSelection rs = get_regions_from_selection_and_entered ();
956 sensitize_all_region_actions (!rs.empty ());
958 _ignore_region_action = true;
960 /* Look through the regions that are selected and make notes about what we have got */
962 bool have_audio = false;
963 bool have_midi = false;
964 bool have_locked = false;
965 bool have_unlocked = false;
966 bool have_position_lock_style_audio = false;
967 bool have_position_lock_style_music = false;
968 bool have_muted = false;
969 bool have_unmuted = false;
970 bool have_opaque = false;
971 bool have_non_opaque = false;
972 bool have_not_at_natural_position = false;
973 bool have_envelope_visible = false;
974 bool have_envelope_invisible = false;
975 bool have_envelope_active = false;
976 bool have_envelope_inactive = false;
977 bool have_non_unity_scale_amplitude = false;
979 for (list<RegionView*>::const_iterator i = rs.begin(); i != rs.end(); ++i) {
981 boost::shared_ptr<Region> r = (*i)->region ();
982 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
988 if (boost::dynamic_pointer_cast<MidiRegion> (r)) {
995 have_unlocked = true;
998 if (r->position_lock_style() == MusicTime) {
999 have_position_lock_style_music = true;
1001 have_position_lock_style_audio = true;
1007 have_unmuted = true;
1013 have_non_opaque = true;
1016 if (!r->at_natural_position()) {
1017 have_not_at_natural_position = true;
1021 /* its a bit unfortunate that "envelope visible" is a view-only
1022 property. we have to find the regionview to able to check
1023 its current setting.
1026 have_envelope_invisible = true;
1029 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
1030 if (arv && arv->envelope_visible()) {
1031 have_envelope_visible = true;
1035 if (ar->envelope_active()) {
1036 have_envelope_active = true;
1038 have_envelope_inactive = true;
1041 if (ar->scale_amplitude() != 1) {
1042 have_non_unity_scale_amplitude = true;
1047 if (rs.size() > 1) {
1048 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1049 _region_actions->get_action("show-region-properties")->set_sensitive (false);
1050 _region_actions->get_action("rename-region")->set_sensitive (false);
1051 } else if (rs.size() == 1) {
1052 _region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
1053 _region_actions->get_action("close-region-gaps")->set_sensitive (false);
1057 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1058 _region_actions->get_action("quantize-region")->set_sensitive (false);
1059 _region_actions->get_action("fork-region")->set_sensitive (false);
1062 if (_edit_point == EditAtMouse) {
1063 _region_actions->get_action("set-region-sync-position")->set_sensitive (false);
1064 _region_actions->get_action("trim-front")->set_sensitive (false);
1065 _region_actions->get_action("trim-back")->set_sensitive (false);
1066 _region_actions->get_action("split-region")->set_sensitive (false);
1067 _region_actions->get_action("place-transient")->set_sensitive (false);
1072 if (have_envelope_visible && !have_envelope_invisible) {
1073 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-visible"))->set_active ();
1074 } else if (have_envelope_visible && have_envelope_invisible) {
1075 // _region_actions->get_action("toggle-region-gain-envelope-visible")->set_inconsistent ();
1078 if (have_envelope_active && !have_envelope_inactive) {
1079 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active ();
1080 } else if (have_envelope_active && have_envelope_inactive) {
1081 // _region_actions->get_action("toggle-region-gain-envelope-active")->set_inconsistent ();
1086 _region_actions->get_action("analyze-region")->set_sensitive (false);
1087 _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
1088 _region_actions->get_action("toggle-region-gain-envelope-visible")->set_sensitive (false);
1089 _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
1093 if (!have_non_unity_scale_amplitude || !have_audio) {
1094 _region_actions->get_action("reset-region-scale-amplitude")->set_sensitive (false);
1097 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"))->set_active (have_locked && !have_unlocked);
1098 if (have_locked && have_unlocked) {
1099 // _region_actions->get_action("toggle-region-lock")->set_inconsistent ();
1102 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"))->set_active (have_position_lock_style_music && !have_position_lock_style_audio);
1104 if (have_position_lock_style_music && have_position_lock_style_audio) {
1105 // _region_actions->get_action("toggle-region-lock-style")->set_inconsistent ();
1108 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"))->set_active (have_muted && !have_unmuted);
1109 if (have_muted && have_unmuted) {
1110 // _region_actions->get_action("toggle-region-mute")->set_inconsistent ();
1113 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"))->set_active (have_opaque && !have_non_opaque);
1114 if (have_opaque && have_non_opaque) {
1115 // _region_actions->get_action("toggle-opaque-region")->set_inconsistent ();
1118 if (!have_not_at_natural_position) {
1119 _region_actions->get_action("naturalize-region")->set_sensitive (false);
1122 /* XXX: should also check that there is a track of the appropriate type for the selected region */
1123 if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
1124 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (false);
1126 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (true);
1129 _ignore_region_action = false;
1131 _all_region_actions_sensitized = false;
1136 Editor::region_selection_changed ()
1138 _regions->block_change_connection (true);
1139 editor_regions_selection_changed_connection.block(true);
1141 if (_region_selection_change_updates_region_list) {
1142 _regions->unselect_all ();
1145 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1146 (*i)->set_selected_regionviews (selection->regions);
1149 if (_region_selection_change_updates_region_list) {
1150 _regions->set_selected (selection->regions);
1153 _regions->block_change_connection (false);
1154 editor_regions_selection_changed_connection.block(false);
1156 if (!_all_region_actions_sensitized) {
1157 /* This selection change might have changed what region actions
1158 are allowed, so sensitize them all in case a key is pressed.
1160 sensitize_all_region_actions (true);
1165 Editor::point_selection_changed ()
1167 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1168 (*i)->set_selected_points (selection->points);
1173 Editor::select_all_in_track (Selection::Operation op)
1175 list<Selectable *> touched;
1177 if (!clicked_routeview) {
1181 clicked_routeview->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1184 case Selection::Toggle:
1185 selection->add (touched);
1187 case Selection::Set:
1188 selection->set (touched);
1190 case Selection::Extend:
1191 /* meaningless, because we're selecting everything */
1193 case Selection::Add:
1194 selection->add (touched);
1200 Editor::select_all (Selection::Operation op)
1202 list<Selectable *> touched;
1204 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1205 if ((*iter)->hidden()) {
1208 (*iter)->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1210 begin_reversible_command (_("select all"));
1212 case Selection::Add:
1213 selection->add (touched);
1215 case Selection::Toggle:
1216 selection->add (touched);
1218 case Selection::Set:
1219 selection->set (touched);
1221 case Selection::Extend:
1222 /* meaningless, because we're selecting everything */
1225 commit_reversible_command ();
1228 Editor::invert_selection_in_track ()
1230 list<Selectable *> touched;
1232 if (!clicked_routeview) {
1236 clicked_routeview->get_inverted_selectables (*selection, touched);
1237 selection->set (touched);
1241 Editor::invert_selection ()
1243 list<Selectable *> touched;
1245 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1246 if ((*iter)->hidden()) {
1249 (*iter)->get_inverted_selectables (*selection, touched);
1252 selection->set (touched);
1255 /** @param start Start time in session frames.
1256 * @param end End time in session frames.
1257 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
1258 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
1259 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
1260 * within the region are already selected.
1263 Editor::select_all_within (
1264 framepos_t start, framepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected
1267 list<Selectable*> found;
1269 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1271 if ((*iter)->hidden()) {
1275 (*iter)->get_selectables (start, end, top, bot, found);
1278 if (found.empty()) {
1282 if (preserve_if_selected && op != Selection::Toggle) {
1283 list<Selectable*>::iterator i = found.begin();
1284 while (i != found.end() && (*i)->get_selected()) {
1288 if (i == found.end()) {
1293 begin_reversible_command (_("select all within"));
1295 case Selection::Add:
1296 selection->add (found);
1298 case Selection::Toggle:
1299 selection->toggle (found);
1301 case Selection::Set:
1302 selection->set (found);
1304 case Selection::Extend:
1305 /* not defined yet */
1309 commit_reversible_command ();
1311 return !found.empty();
1315 Editor::set_selection_from_region ()
1317 if (selection->regions.empty()) {
1321 selection->set (selection->regions.start(), selection->regions.end_frame());
1322 if (!Profile->get_sae()) {
1323 set_mouse_mode (Editing::MouseRange, false);
1328 Editor::set_selection_from_punch()
1332 if ((location = _session->locations()->auto_punch_location()) == 0) {
1336 set_selection_from_range (*location);
1340 Editor::set_selection_from_loop()
1344 if ((location = _session->locations()->auto_loop_location()) == 0) {
1347 set_selection_from_range (*location);
1351 Editor::set_selection_from_range (Location& loc)
1353 begin_reversible_command (_("set selection from range"));
1354 selection->set (loc.start(), loc.end());
1355 commit_reversible_command ();
1357 if (!Profile->get_sae()) {
1358 set_mouse_mode (Editing::MouseRange, false);
1363 Editor::select_all_selectables_using_time_selection ()
1365 list<Selectable *> touched;
1367 if (selection->time.empty()) {
1371 framepos_t start = selection->time[clicked_selection].start;
1372 framepos_t end = selection->time[clicked_selection].end;
1374 if (end - start < 1) {
1380 if (selection->tracks.empty()) {
1383 ts = &selection->tracks;
1386 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1387 if ((*iter)->hidden()) {
1390 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1393 begin_reversible_command (_("select all from range"));
1394 selection->set (touched);
1395 commit_reversible_command ();
1400 Editor::select_all_selectables_using_punch()
1402 Location* location = _session->locations()->auto_punch_location();
1403 list<Selectable *> touched;
1405 if (location == 0 || (location->end() - location->start() <= 1)) {
1412 if (selection->tracks.empty()) {
1415 ts = &selection->tracks;
1418 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1419 if ((*iter)->hidden()) {
1422 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1424 begin_reversible_command (_("select all from punch"));
1425 selection->set (touched);
1426 commit_reversible_command ();
1431 Editor::select_all_selectables_using_loop()
1433 Location* location = _session->locations()->auto_loop_location();
1434 list<Selectable *> touched;
1436 if (location == 0 || (location->end() - location->start() <= 1)) {
1443 if (selection->tracks.empty()) {
1446 ts = &selection->tracks;
1449 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1450 if ((*iter)->hidden()) {
1453 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1455 begin_reversible_command (_("select all from loop"));
1456 selection->set (touched);
1457 commit_reversible_command ();
1462 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1466 list<Selectable *> touched;
1469 begin_reversible_command (_("select all after cursor"));
1470 start = cursor->current_frame ;
1471 end = _session->current_end_frame();
1473 if (cursor->current_frame > 0) {
1474 begin_reversible_command (_("select all before cursor"));
1476 end = cursor->current_frame - 1;
1485 if (selection->tracks.empty()) {
1488 ts = &selection->tracks;
1491 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1492 if ((*iter)->hidden()) {
1495 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1497 selection->set (touched);
1498 commit_reversible_command ();
1502 Editor::select_all_selectables_using_edit (bool after)
1506 list<Selectable *> touched;
1509 begin_reversible_command (_("select all after edit"));
1510 start = get_preferred_edit_position();
1511 end = _session->current_end_frame();
1513 if ((end = get_preferred_edit_position()) > 1) {
1514 begin_reversible_command (_("select all before edit"));
1525 if (selection->tracks.empty()) {
1528 ts = &selection->tracks;
1531 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1532 if ((*iter)->hidden()) {
1535 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1537 selection->set (touched);
1538 commit_reversible_command ();
1542 Editor::select_all_selectables_between (bool /*within*/)
1546 list<Selectable *> touched;
1548 if (!get_edit_op_range (start, end)) {
1554 if (selection->tracks.empty()) {
1557 ts = &selection->tracks;
1560 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1561 if ((*iter)->hidden()) {
1564 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1567 selection->set (touched);
1571 Editor::select_range_between ()
1576 if (mouse_mode == MouseRange && !selection->time.empty()) {
1577 selection->clear_time ();
1580 if (!get_edit_op_range (start, end)) {
1584 set_mouse_mode (MouseRange);
1585 selection->set (start, end);
1589 Editor::get_edit_op_range (framepos_t& start, framepos_t& end) const
1594 /* in range mode, use any existing selection */
1596 if (mouse_mode == MouseRange && !selection->time.empty()) {
1597 /* we know that these are ordered */
1598 start = selection->time.start();
1599 end = selection->time.end_frame();
1603 if (!mouse_frame (m, ignored)) {
1604 /* mouse is not in a canvas, try playhead+selected marker.
1605 this is probably most true when using menus.
1608 if (selection->markers.empty()) {
1612 start = selection->markers.front()->position();
1613 end = _session->audible_frame();
1617 switch (_edit_point) {
1618 case EditAtPlayhead:
1619 if (selection->markers.empty()) {
1620 /* use mouse + playhead */
1622 end = _session->audible_frame();
1624 /* use playhead + selected marker */
1625 start = _session->audible_frame();
1626 end = selection->markers.front()->position();
1631 /* use mouse + selected marker */
1632 if (selection->markers.empty()) {
1634 end = _session->audible_frame();
1636 start = selection->markers.front()->position();
1641 case EditAtSelectedMarker:
1642 /* use mouse + selected marker */
1643 if (selection->markers.empty()) {
1645 MessageDialog win (_("No edit range defined"),
1650 win.set_secondary_text (
1651 _("the edit point is Selected Marker\nbut there is no selected marker."));
1654 win.set_default_response (RESPONSE_CLOSE);
1655 win.set_position (Gtk::WIN_POS_MOUSE);
1660 return false; // NO RANGE
1662 start = selection->markers.front()->position();
1676 /* turn range into one delimited by start...end,
1686 Editor::deselect_all ()
1688 selection->clear ();
1692 Editor::select_range_around_region (RegionView* rv)
1696 selection->set (&rv->get_time_axis_view());
1698 selection->time.clear ();
1699 boost::shared_ptr<Region> r = rv->region ();
1700 return selection->set (r->position(), r->position() + r->length());