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"
39 #include "editor_cursors.h"
40 #include "midi_region_view.h"
45 using namespace ARDOUR;
49 using namespace Gtkmm2ext;
50 using namespace Editing;
52 struct TrackViewByPositionSorter
54 bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
55 return a->y_position() < b->y_position();
60 Editor::extend_selection_to_track (TimeAxisView& view)
62 if (selection->selected (&view)) {
63 /* already selected, do nothing */
67 if (selection->tracks.empty()) {
69 if (!selection->selected (&view)) {
70 selection->set (&view);
77 /* something is already selected, so figure out which range of things to add */
79 TrackViewList to_be_added;
80 TrackViewList sorted = track_views;
81 TrackViewByPositionSorter cmp;
82 bool passed_clicked = false;
87 if (!selection->selected (&view)) {
88 to_be_added.push_back (&view);
91 /* figure out if we should go forward or backwards */
93 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
96 passed_clicked = true;
99 if (selection->selected (*i)) {
100 if (passed_clicked) {
109 passed_clicked = false;
113 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
116 passed_clicked = true;
120 if (passed_clicked) {
121 if ((*i)->hidden()) {
124 if (selection->selected (*i)) {
126 } else if (!(*i)->hidden()) {
127 to_be_added.push_back (*i);
134 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
137 passed_clicked = true;
141 if (passed_clicked) {
143 if ((*r)->hidden()) {
147 if (selection->selected (*r)) {
149 } else if (!(*r)->hidden()) {
150 to_be_added.push_back (*r);
156 if (!to_be_added.empty()) {
157 selection->add (to_be_added);
165 Editor::select_all_tracks ()
167 TrackViewList visible_views;
168 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
169 if ((*i)->marked_for_display()) {
170 visible_views.push_back (*i);
173 selection->set (visible_views);
176 /** Select clicked_axisview, unless there are no currently selected
177 * tracks, in which case nothing will happen unless `force' is true.
180 Editor::set_selected_track_as_side_effect (Selection::Operation op, bool /*force*/)
182 if (!clicked_axisview) {
187 if (!clicked_routeview) {
191 bool had_tracks = !selection->tracks.empty();
192 RouteGroup* group = clicked_routeview->route()->route_group();
193 RouteGroup& arg (_session->all_route_group());
196 case Selection::Toggle:
197 if (selection->selected (clicked_axisview)) {
198 if (arg.is_select() && arg.is_active()) {
199 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
200 selection->remove(*i);
202 } else if (group && group->is_active()) {
203 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
204 if ((*i)->route_group() == group)
205 selection->remove(*i);
208 selection->remove (clicked_axisview);
211 if (arg.is_select() && arg.is_active()) {
212 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
215 } else if (group && group->is_active()) {
216 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
217 if ( (*i)->route_group() == group)
221 selection->add (clicked_axisview);
227 if (!had_tracks && arg.is_select() && arg.is_active()) {
228 /* nothing was selected already, and all group is active etc. so use
231 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
234 } else if (group && group->is_active()) {
235 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
236 if ((*i)->route_group() == group)
240 selection->add (clicked_axisview);
246 if (!had_tracks && arg.is_select() && arg.is_active()) {
247 /* nothing was selected already, and all group is active etc. so use
250 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
253 } else if (group && group->is_active()) {
254 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
255 if ((*i)->route_group() == group)
259 selection->set (clicked_axisview);
263 case Selection::Extend:
265 cerr << ("Editor::set_selected_track_as_side_effect case Selection::Add not yet implemented\n");
269 #else // the older version
271 if (!selection->tracks.empty()) {
272 if (!selection->selected (clicked_axisview)) {
273 selection->add (clicked_axisview);
277 selection->set (clicked_axisview);
283 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
286 case Selection::Toggle:
287 if (selection->selected (&view)) {
289 selection->remove (&view);
292 selection->add (&view);
297 if (!selection->selected (&view)) {
298 selection->add (&view);
303 selection->set (&view);
306 case Selection::Extend:
307 extend_selection_to_track (view);
313 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
315 if (!clicked_routeview) {
323 set_selected_track (*clicked_routeview, op, no_remove);
327 Editor::set_selected_control_point_from_click (Selection::Operation op, bool /*no_remove*/)
329 if (!clicked_control_point) {
335 selection->set (clicked_control_point);
338 selection->add (clicked_control_point);
340 case Selection::Toggle:
341 selection->toggle (clicked_control_point);
343 case Selection::Extend:
352 Editor::get_onscreen_tracks (TrackViewList& tvl)
354 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
355 if ((*i)->y_position() < _canvas_height) {
361 /** Call a slot for a given `basis' track and also for any track that is in the same
362 * active route group with a particular set of properties.
364 * @param sl Slot to call.
365 * @param basis Basis track.
366 * @param prop Properties that active edit groups must share to be included in the map.
370 Editor::mapover_tracks (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
372 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
374 if (route_basis == 0) {
378 set<RouteTimeAxisView*> tracks;
379 tracks.insert (route_basis);
381 RouteGroup* group = route_basis->route()->route_group();
383 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id) ) {
385 /* the basis is a member of an active route group, with the appropriate
386 properties; find other members */
388 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
389 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
390 if (v && v->route()->route_group() == group) {
397 uint32_t const sz = tracks.size ();
399 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
405 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
407 boost::shared_ptr<Playlist> pl;
408 vector<boost::shared_ptr<Region> > results;
410 boost::shared_ptr<Track> tr;
412 if ((tr = tv.track()) == 0) {
417 if (&tv == &basis->get_time_axis_view()) {
418 /* looking in same track as the original */
422 if ((pl = tr->playlist()) != 0) {
423 pl->get_equivalent_regions (basis->region(), results);
426 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
427 if ((marv = tv.view()->find_view (*ir)) != 0) {
428 all_equivs->push_back (marv);
434 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, PBD::PropertyID property) const
436 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_time_axis_view(), property);
438 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
440 equivalent_regions.push_back (basis);
444 Editor::get_equivalent_regions (RegionSelection & basis, PBD::PropertyID prop) const
446 RegionSelection equivalent;
448 for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
450 vector<RegionView*> eq;
453 sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
454 &(*i)->get_time_axis_view(), prop);
456 for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
468 Editor::get_regionview_count_from_region_list (boost::shared_ptr<Region> region)
470 int region_count = 0;
472 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
474 RouteTimeAxisView* tatv;
476 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
478 boost::shared_ptr<Playlist> pl;
479 vector<boost::shared_ptr<Region> > results;
481 boost::shared_ptr<Track> tr;
483 if ((tr = tatv->track()) == 0) {
488 if ((pl = (tr->playlist())) != 0) {
489 pl->get_region_list_equivalent_regions (region, results);
492 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
493 if ((marv = tatv->view()->find_view (*ir)) != 0) {
506 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool /*no_track_remove*/)
508 vector<RegionView*> all_equivalent_regions;
511 if (!clicked_regionview || !clicked_routeview) {
516 button_release_can_deselect = false;
519 if (op == Selection::Toggle || op == Selection::Set) {
523 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;
534 if (button_release_can_deselect) {
536 /* just remove this one region, but only on a permitted button release */
538 selection->remove (clicked_regionview);
541 /* no more deselect action on button release till a new press
542 finds an already selected object.
545 button_release_can_deselect = false;
553 if (selection->selected (clicked_routeview)) {
554 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
556 all_equivalent_regions.push_back (clicked_regionview);
559 /* add all the equivalent regions, but only on button press */
561 if (!all_equivalent_regions.empty()) {
565 selection->add (all_equivalent_regions);
571 if (!selection->selected (clicked_regionview)) {
572 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
573 selection->set (all_equivalent_regions);
576 /* no commit necessary: clicked on an already selected region */
586 } else if (op == Selection::Extend) {
588 list<Selectable*> results;
589 framepos_t last_frame;
590 framepos_t first_frame;
591 bool same_track = false;
593 /* 1. find the last selected regionview in the track that was clicked in */
596 first_frame = max_framepos;
598 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
599 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
601 if ((*x)->region()->last_frame() > last_frame) {
602 last_frame = (*x)->region()->last_frame();
605 if ((*x)->region()->first_frame() < first_frame) {
606 first_frame = (*x)->region()->first_frame();
615 /* 2. figure out the boundaries for our search for new objects */
617 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
619 if (last_frame < clicked_regionview->region()->first_frame()) {
620 first_frame = last_frame;
621 last_frame = clicked_regionview->region()->last_frame();
623 last_frame = first_frame;
624 first_frame = clicked_regionview->region()->first_frame();
628 case OverlapExternal:
629 if (last_frame < clicked_regionview->region()->first_frame()) {
630 first_frame = last_frame;
631 last_frame = clicked_regionview->region()->last_frame();
633 last_frame = first_frame;
634 first_frame = clicked_regionview->region()->first_frame();
638 case OverlapInternal:
639 if (last_frame < clicked_regionview->region()->first_frame()) {
640 first_frame = last_frame;
641 last_frame = clicked_regionview->region()->last_frame();
643 last_frame = first_frame;
644 first_frame = clicked_regionview->region()->first_frame();
650 /* nothing to do except add clicked region to selection, since it
651 overlaps with the existing selection in this track.
658 /* click in a track that has no regions selected, so extend vertically
659 to pick out all regions that are defined by the existing selection
664 first_frame = clicked_regionview->region()->position();
665 last_frame = clicked_regionview->region()->last_frame();
667 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
668 if ((*i)->region()->position() < first_frame) {
669 first_frame = (*i)->region()->position();
671 if ((*i)->region()->last_frame() + 1 > last_frame) {
672 last_frame = (*i)->region()->last_frame();
677 /* 2. find all the tracks we should select in */
679 set<RouteTimeAxisView*> relevant_tracks;
681 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
682 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
684 relevant_tracks.insert (r);
688 set<RouteTimeAxisView*> already_in_selection;
690 if (relevant_tracks.empty()) {
692 /* no tracks selected .. thus .. if the
693 regionview we're in isn't selected
694 (i.e. we're about to extend to it), then
695 find all tracks between the this one and
699 if (!selection->selected (clicked_regionview)) {
701 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&clicked_regionview->get_time_axis_view());
705 /* add this track to the ones we will search */
707 relevant_tracks.insert (rtv);
709 /* find the track closest to this one that
710 already a selected region.
713 RouteTimeAxisView* closest = 0;
714 int distance = INT_MAX;
715 int key = rtv->route()->order_key ("editor");
717 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
719 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
721 if (artv && artv != rtv) {
723 pair<set<RouteTimeAxisView*>::iterator,bool> result;
725 result = already_in_selection.insert (artv);
728 /* newly added to already_in_selection */
730 int d = artv->route()->order_key ("editor");
734 if (abs (d) < distance) {
744 /* now add all tracks between that one and this one */
746 int okey = closest->route()->order_key ("editor");
752 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
753 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
754 if (artv && artv != rtv) {
756 int k = artv->route()->order_key ("editor");
758 if (k >= okey && k <= key) {
760 /* in range but don't add it if
761 it already has tracks selected.
762 this avoids odd selection
763 behaviour that feels wrong.
766 if (find (already_in_selection.begin(),
767 already_in_selection.end(),
768 artv) == already_in_selection.end()) {
770 relevant_tracks.insert (artv);
780 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
781 one that was clicked.
784 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
785 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
788 /* 4. convert to a vector of regions */
790 vector<RegionView*> regions;
792 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
795 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
796 regions.push_back (arv);
800 if (!regions.empty()) {
801 selection->add (regions);
812 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
814 vector<RegionView*> all_equivalent_regions;
816 get_regions_corresponding_to (region, all_equivalent_regions);
818 if (all_equivalent_regions.empty()) {
822 begin_reversible_command (_("set selected regions"));
825 case Selection::Toggle:
826 /* XXX this is not correct */
827 selection->toggle (all_equivalent_regions);
830 selection->set (all_equivalent_regions);
832 case Selection::Extend:
833 selection->add (all_equivalent_regions);
836 selection->add (all_equivalent_regions);
840 commit_reversible_command () ;
844 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
847 boost::shared_ptr<Region> r (weak_r.lock());
853 if ((rv = sv->find_view (r)) == 0) {
857 /* don't reset the selection if its something other than
858 a single other region.
861 if (selection->regions.size() > 1) {
865 begin_reversible_command (_("set selected regions"));
869 commit_reversible_command () ;
875 Editor::track_selection_changed ()
877 switch (selection->tracks.size()) {
881 set_selected_mixer_strip (*(selection->tracks.front()));
885 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
887 bool yn = (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end());
889 (*i)->set_selected (yn);
891 TimeAxisView::Children c = (*i)->get_child_list ();
892 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
893 (*j)->set_selected (find (selection->tracks.begin(), selection->tracks.end(), j->get()) != selection->tracks.end());
897 ((mouse_mode == MouseRange) ||
898 ((mouse_mode == MouseObject) && (_join_object_range_state == JOIN_OBJECT_RANGE_OBJECT)))) {
899 (*i)->reshow_selection (selection->time);
901 (*i)->hide_selection ();
905 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
909 Editor::time_selection_changed ()
911 if (Profile->get_sae()) {
915 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
916 (*i)->hide_selection ();
919 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
920 (*i)->show_selection (selection->time);
923 if (selection->time.empty()) {
924 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
926 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
930 /** Set all region actions to have a given sensitivity */
932 Editor::sensitize_all_region_actions (bool s)
934 Glib::ListHandle<Glib::RefPtr<Action> > all = _region_actions->get_actions ();
936 for (Glib::ListHandle<Glib::RefPtr<Action> >::iterator i = all.begin(); i != all.end(); ++i) {
937 (*i)->set_sensitive (s);
940 _all_region_actions_sensitized = s;
943 /** Sensitize region-based actions based on the selection ONLY, ignoring the entered_regionview.
944 * This method should be called just before displaying a Region menu. When a Region menu is not
945 * currently being shown, all region actions are sensitized so that hotkey-triggered actions
946 * on entered_regionviews work without having to check sensitivity every time the selection or
947 * entered_regionview changes.
949 * This method also sets up toggle action state as appropriate.
952 Editor::sensitize_the_right_region_actions ()
954 if ((mouse_mode == MouseRange) || (mouse_mode != MouseObject && _join_object_range_state == JOIN_OBJECT_RANGE_RANGE)) {
955 sensitize_all_region_actions (false);
956 if (!selection->time.empty()) {
957 _region_actions->get_action("split-region")->set_sensitive (true);
961 } else if (mouse_mode != MouseObject) {
962 sensitize_all_region_actions (false);
966 /* We get here if we are in Object mode */
968 RegionSelection rs = get_regions_from_selection_and_entered ();
969 sensitize_all_region_actions (!rs.empty ());
971 _ignore_region_action = true;
973 /* Look through the regions that are selected and make notes about what we have got */
975 bool have_audio = false;
976 bool have_midi = false;
977 bool have_locked = false;
978 bool have_unlocked = false;
979 bool have_position_lock_style_audio = false;
980 bool have_position_lock_style_music = false;
981 bool have_muted = false;
982 bool have_unmuted = false;
983 bool have_opaque = false;
984 bool have_non_opaque = false;
985 bool have_not_at_natural_position = false;
986 bool have_envelope_visible = false;
987 bool have_envelope_invisible = false;
988 bool have_envelope_active = false;
989 bool have_envelope_inactive = false;
990 bool have_non_unity_scale_amplitude = false;
991 bool have_compound_regions = false;
993 for (list<RegionView*>::const_iterator i = rs.begin(); i != rs.end(); ++i) {
995 boost::shared_ptr<Region> r = (*i)->region ();
996 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
1002 if (boost::dynamic_pointer_cast<MidiRegion> (r)) {
1006 if (r->is_compound()) {
1007 have_compound_regions = true;
1013 have_unlocked = true;
1016 if (r->position_lock_style() == MusicTime) {
1017 have_position_lock_style_music = true;
1019 have_position_lock_style_audio = true;
1025 have_unmuted = true;
1031 have_non_opaque = true;
1034 if (!r->at_natural_position()) {
1035 have_not_at_natural_position = true;
1039 /* its a bit unfortunate that "envelope visible" is a view-only
1040 property. we have to find the regionview to able to check
1041 its current setting.
1044 have_envelope_invisible = true;
1047 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
1048 if (arv && arv->envelope_visible()) {
1049 have_envelope_visible = true;
1053 if (ar->envelope_active()) {
1054 have_envelope_active = true;
1056 have_envelope_inactive = true;
1059 if (ar->scale_amplitude() != 1) {
1060 have_non_unity_scale_amplitude = true;
1065 if (rs.size() > 1) {
1066 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1067 _region_actions->get_action("show-region-properties")->set_sensitive (false);
1068 _region_actions->get_action("rename-region")->set_sensitive (false);
1070 _region_actions->get_action("combine-regions")->set_sensitive (true);
1072 _region_actions->get_action("combine-regions")->set_sensitive (false);
1074 } else if (rs.size() == 1) {
1075 _region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
1076 _region_actions->get_action("close-region-gaps")->set_sensitive (false);
1077 _region_actions->get_action("combine-regions")->set_sensitive (false);
1081 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1082 _region_actions->get_action("quantize-region")->set_sensitive (false);
1083 _region_actions->get_action("fork-region")->set_sensitive (false);
1084 _region_actions->get_action("transpose-region")->set_sensitive (false);
1087 if (_edit_point == EditAtMouse) {
1088 _region_actions->get_action("set-region-sync-position")->set_sensitive (false);
1089 _region_actions->get_action("trim-front")->set_sensitive (false);
1090 _region_actions->get_action("trim-back")->set_sensitive (false);
1091 _region_actions->get_action("split-region")->set_sensitive (false);
1092 _region_actions->get_action("place-transient")->set_sensitive (false);
1095 if (have_compound_regions) {
1096 _region_actions->get_action("uncombine-regions")->set_sensitive (true);
1098 _region_actions->get_action("uncombine-regions")->set_sensitive (false);
1103 if (have_envelope_visible && !have_envelope_invisible) {
1104 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-visible"))->set_active ();
1105 } else if (have_envelope_visible && have_envelope_invisible) {
1106 // _region_actions->get_action("toggle-region-gain-envelope-visible")->set_inconsistent ();
1109 if (have_envelope_active && !have_envelope_inactive) {
1110 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active ();
1111 } else if (have_envelope_active && have_envelope_inactive) {
1112 // _region_actions->get_action("toggle-region-gain-envelope-active")->set_inconsistent ();
1117 _region_actions->get_action("analyze-region")->set_sensitive (false);
1118 _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
1119 _region_actions->get_action("toggle-region-gain-envelope-visible")->set_sensitive (false);
1120 _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
1121 _region_actions->get_action("pitch-shift-region")->set_sensitive (false);
1125 if (!have_non_unity_scale_amplitude || !have_audio) {
1126 _region_actions->get_action("reset-region-scale-amplitude")->set_sensitive (false);
1129 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"))->set_active (have_locked && !have_unlocked);
1130 if (have_locked && have_unlocked) {
1131 // _region_actions->get_action("toggle-region-lock")->set_inconsistent ();
1134 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);
1136 if (have_position_lock_style_music && have_position_lock_style_audio) {
1137 // _region_actions->get_action("toggle-region-lock-style")->set_inconsistent ();
1140 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"))->set_active (have_muted && !have_unmuted);
1141 if (have_muted && have_unmuted) {
1142 // _region_actions->get_action("toggle-region-mute")->set_inconsistent ();
1145 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"))->set_active (have_opaque && !have_non_opaque);
1146 if (have_opaque && have_non_opaque) {
1147 // _region_actions->get_action("toggle-opaque-region")->set_inconsistent ();
1150 if (!have_not_at_natural_position) {
1151 _region_actions->get_action("naturalize-region")->set_sensitive (false);
1154 /* XXX: should also check that there is a track of the appropriate type for the selected region */
1155 if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
1156 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (false);
1158 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (true);
1161 _ignore_region_action = false;
1163 _all_region_actions_sensitized = false;
1168 Editor::region_selection_changed ()
1170 _regions->block_change_connection (true);
1171 editor_regions_selection_changed_connection.block(true);
1173 if (_region_selection_change_updates_region_list) {
1174 _regions->unselect_all ();
1177 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1178 (*i)->set_selected_regionviews (selection->regions);
1181 if (_region_selection_change_updates_region_list) {
1182 _regions->set_selected (selection->regions);
1185 _regions->block_change_connection (false);
1186 editor_regions_selection_changed_connection.block(false);
1188 if (!_all_region_actions_sensitized) {
1189 /* This selection change might have changed what region actions
1190 are allowed, so sensitize them all in case a key is pressed.
1192 sensitize_all_region_actions (true);
1197 Editor::point_selection_changed ()
1199 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1200 (*i)->set_selected_points (selection->points);
1205 Editor::select_all_in_track (Selection::Operation op)
1207 list<Selectable *> touched;
1209 if (!clicked_routeview) {
1213 clicked_routeview->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1216 case Selection::Toggle:
1217 selection->add (touched);
1219 case Selection::Set:
1220 selection->set (touched);
1222 case Selection::Extend:
1223 /* meaningless, because we're selecting everything */
1225 case Selection::Add:
1226 selection->add (touched);
1232 Editor::select_all_internal_edit (Selection::Operation)
1234 /* currently limited to MIDI only */
1236 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1237 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1239 mrv->select_all_notes ();
1245 Editor::select_all (Selection::Operation op)
1247 list<Selectable *> touched;
1249 if (_internal_editing) {
1250 select_all_internal_edit (op);
1254 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1255 if ((*iter)->hidden()) {
1258 (*iter)->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1260 begin_reversible_command (_("select all"));
1262 case Selection::Add:
1263 selection->add (touched);
1265 case Selection::Toggle:
1266 selection->add (touched);
1268 case Selection::Set:
1269 selection->set (touched);
1271 case Selection::Extend:
1272 /* meaningless, because we're selecting everything */
1275 commit_reversible_command ();
1278 Editor::invert_selection_in_track ()
1280 list<Selectable *> touched;
1282 if (!clicked_routeview) {
1286 clicked_routeview->get_inverted_selectables (*selection, touched);
1287 selection->set (touched);
1291 Editor::invert_selection ()
1293 list<Selectable *> touched;
1295 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1296 if ((*iter)->hidden()) {
1299 (*iter)->get_inverted_selectables (*selection, touched);
1302 selection->set (touched);
1305 /** @param start Start time in session frames.
1306 * @param end End time in session frames.
1307 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
1308 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
1309 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
1310 * within the region are already selected.
1313 Editor::select_all_within (framepos_t start, framepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected)
1315 list<Selectable*> found;
1317 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1319 if ((*iter)->hidden()) {
1323 (*iter)->get_selectables (start, end, top, bot, found);
1326 if (found.empty()) {
1330 if (preserve_if_selected && op != Selection::Toggle) {
1331 list<Selectable*>::iterator i = found.begin();
1332 while (i != found.end() && (*i)->get_selected()) {
1336 if (i == found.end()) {
1341 begin_reversible_command (_("select all within"));
1343 case Selection::Add:
1344 selection->add (found);
1346 case Selection::Toggle:
1347 selection->toggle (found);
1349 case Selection::Set:
1350 selection->set (found);
1352 case Selection::Extend:
1353 /* not defined yet */
1357 commit_reversible_command ();
1361 Editor::set_selection_from_region ()
1363 if (selection->regions.empty()) {
1367 selection->set (selection->regions.start(), selection->regions.end_frame());
1368 if (!Profile->get_sae()) {
1369 set_mouse_mode (Editing::MouseRange, false);
1374 Editor::set_selection_from_punch()
1378 if ((location = _session->locations()->auto_punch_location()) == 0) {
1382 set_selection_from_range (*location);
1386 Editor::set_selection_from_loop()
1390 if ((location = _session->locations()->auto_loop_location()) == 0) {
1393 set_selection_from_range (*location);
1397 Editor::set_selection_from_range (Location& loc)
1399 begin_reversible_command (_("set selection from range"));
1400 selection->set (loc.start(), loc.end());
1401 commit_reversible_command ();
1403 if (!Profile->get_sae()) {
1404 set_mouse_mode (Editing::MouseRange, false);
1409 Editor::select_all_selectables_using_time_selection ()
1411 list<Selectable *> touched;
1413 if (selection->time.empty()) {
1417 framepos_t start = selection->time[clicked_selection].start;
1418 framepos_t end = selection->time[clicked_selection].end;
1420 if (end - start < 1) {
1426 if (selection->tracks.empty()) {
1429 ts = &selection->tracks;
1432 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1433 if ((*iter)->hidden()) {
1436 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1439 begin_reversible_command (_("select all from range"));
1440 selection->set (touched);
1441 commit_reversible_command ();
1446 Editor::select_all_selectables_using_punch()
1448 Location* location = _session->locations()->auto_punch_location();
1449 list<Selectable *> touched;
1451 if (location == 0 || (location->end() - location->start() <= 1)) {
1458 if (selection->tracks.empty()) {
1461 ts = &selection->tracks;
1464 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1465 if ((*iter)->hidden()) {
1468 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1470 begin_reversible_command (_("select all from punch"));
1471 selection->set (touched);
1472 commit_reversible_command ();
1477 Editor::select_all_selectables_using_loop()
1479 Location* location = _session->locations()->auto_loop_location();
1480 list<Selectable *> touched;
1482 if (location == 0 || (location->end() - location->start() <= 1)) {
1489 if (selection->tracks.empty()) {
1492 ts = &selection->tracks;
1495 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1496 if ((*iter)->hidden()) {
1499 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1501 begin_reversible_command (_("select all from loop"));
1502 selection->set (touched);
1503 commit_reversible_command ();
1508 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1512 list<Selectable *> touched;
1515 begin_reversible_command (_("select all after cursor"));
1516 start = cursor->current_frame;
1517 end = _session->current_end_frame();
1519 if (cursor->current_frame > 0) {
1520 begin_reversible_command (_("select all before cursor"));
1522 end = cursor->current_frame - 1;
1531 if (selection->tracks.empty()) {
1534 ts = &selection->tracks;
1537 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1538 if ((*iter)->hidden()) {
1541 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1543 selection->set (touched);
1544 commit_reversible_command ();
1548 Editor::select_all_selectables_using_edit (bool after)
1552 list<Selectable *> touched;
1555 begin_reversible_command (_("select all after edit"));
1556 start = get_preferred_edit_position();
1557 end = _session->current_end_frame();
1559 if ((end = get_preferred_edit_position()) > 1) {
1560 begin_reversible_command (_("select all before edit"));
1571 if (selection->tracks.empty()) {
1574 ts = &selection->tracks;
1577 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1578 if ((*iter)->hidden()) {
1581 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1583 selection->set (touched);
1584 commit_reversible_command ();
1588 Editor::select_all_selectables_between (bool /*within*/)
1592 list<Selectable *> touched;
1594 if (!get_edit_op_range (start, end)) {
1600 if (selection->tracks.empty()) {
1603 ts = &selection->tracks;
1606 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1607 if ((*iter)->hidden()) {
1610 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1613 selection->set (touched);
1617 Editor::select_range_between ()
1622 if (mouse_mode == MouseRange && !selection->time.empty()) {
1623 selection->clear_time ();
1626 if (!get_edit_op_range (start, end)) {
1630 set_mouse_mode (MouseRange);
1631 selection->set (start, end);
1635 Editor::get_edit_op_range (framepos_t& start, framepos_t& end) const
1640 /* in range mode, use any existing selection */
1642 if (mouse_mode == MouseRange && !selection->time.empty()) {
1643 /* we know that these are ordered */
1644 start = selection->time.start();
1645 end = selection->time.end_frame();
1649 if (!mouse_frame (m, ignored)) {
1650 /* mouse is not in a canvas, try playhead+selected marker.
1651 this is probably most true when using menus.
1654 if (selection->markers.empty()) {
1658 start = selection->markers.front()->position();
1659 end = _session->audible_frame();
1663 switch (_edit_point) {
1664 case EditAtPlayhead:
1665 if (selection->markers.empty()) {
1666 /* use mouse + playhead */
1668 end = _session->audible_frame();
1670 /* use playhead + selected marker */
1671 start = _session->audible_frame();
1672 end = selection->markers.front()->position();
1677 /* use mouse + selected marker */
1678 if (selection->markers.empty()) {
1680 end = _session->audible_frame();
1682 start = selection->markers.front()->position();
1687 case EditAtSelectedMarker:
1688 /* use mouse + selected marker */
1689 if (selection->markers.empty()) {
1691 MessageDialog win (_("No edit range defined"),
1696 win.set_secondary_text (
1697 _("the edit point is Selected Marker\nbut there is no selected marker."));
1700 win.set_default_response (RESPONSE_CLOSE);
1701 win.set_position (Gtk::WIN_POS_MOUSE);
1706 return false; // NO RANGE
1708 start = selection->markers.front()->position();
1722 /* turn range into one delimited by start...end,
1732 Editor::deselect_all ()
1734 selection->clear ();
1738 Editor::select_range_around_region (RegionView* rv)
1742 selection->set (&rv->get_time_axis_view());
1744 selection->time.clear ();
1745 boost::shared_ptr<Region> r = rv->region ();
1746 return selection->set (r->position(), r->position() + r->length());