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) {
1089 _region_actions->get_action("set-region-sync-position")->set_sensitive (false);
1090 _region_actions->get_action("trim-front")->set_sensitive (false);
1091 _region_actions->get_action("trim-back")->set_sensitive (false);
1092 _region_actions->get_action("split-region")->set_sensitive (false);
1094 _region_actions->get_action("place-transient")->set_sensitive (false);
1097 if (have_compound_regions) {
1098 _region_actions->get_action("uncombine-regions")->set_sensitive (true);
1100 _region_actions->get_action("uncombine-regions")->set_sensitive (false);
1105 if (have_envelope_visible && !have_envelope_invisible) {
1106 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-visible"))->set_active ();
1107 } else if (have_envelope_visible && have_envelope_invisible) {
1108 // _region_actions->get_action("toggle-region-gain-envelope-visible")->set_inconsistent ();
1111 if (have_envelope_active && !have_envelope_inactive) {
1112 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active ();
1113 } else if (have_envelope_active && have_envelope_inactive) {
1114 // _region_actions->get_action("toggle-region-gain-envelope-active")->set_inconsistent ();
1119 _region_actions->get_action("analyze-region")->set_sensitive (false);
1120 _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
1121 _region_actions->get_action("toggle-region-gain-envelope-visible")->set_sensitive (false);
1122 _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
1123 _region_actions->get_action("pitch-shift-region")->set_sensitive (false);
1127 if (!have_non_unity_scale_amplitude || !have_audio) {
1128 _region_actions->get_action("reset-region-scale-amplitude")->set_sensitive (false);
1131 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"))->set_active (have_locked && !have_unlocked);
1132 if (have_locked && have_unlocked) {
1133 // _region_actions->get_action("toggle-region-lock")->set_inconsistent ();
1136 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);
1138 if (have_position_lock_style_music && have_position_lock_style_audio) {
1139 // _region_actions->get_action("toggle-region-lock-style")->set_inconsistent ();
1142 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"))->set_active (have_muted && !have_unmuted);
1143 if (have_muted && have_unmuted) {
1144 // _region_actions->get_action("toggle-region-mute")->set_inconsistent ();
1147 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"))->set_active (have_opaque && !have_non_opaque);
1148 if (have_opaque && have_non_opaque) {
1149 // _region_actions->get_action("toggle-opaque-region")->set_inconsistent ();
1152 if (!have_not_at_natural_position) {
1153 _region_actions->get_action("naturalize-region")->set_sensitive (false);
1156 /* XXX: should also check that there is a track of the appropriate type for the selected region */
1157 if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
1158 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (false);
1160 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (true);
1163 _ignore_region_action = false;
1165 _all_region_actions_sensitized = false;
1170 Editor::region_selection_changed ()
1172 _regions->block_change_connection (true);
1173 editor_regions_selection_changed_connection.block(true);
1175 if (_region_selection_change_updates_region_list) {
1176 _regions->unselect_all ();
1179 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1180 (*i)->set_selected_regionviews (selection->regions);
1183 if (_region_selection_change_updates_region_list) {
1184 _regions->set_selected (selection->regions);
1187 _regions->block_change_connection (false);
1188 editor_regions_selection_changed_connection.block(false);
1190 sensitize_the_right_region_actions ();
1194 Editor::point_selection_changed ()
1196 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1197 (*i)->set_selected_points (selection->points);
1202 Editor::select_all_in_track (Selection::Operation op)
1204 list<Selectable *> touched;
1206 if (!clicked_routeview) {
1210 clicked_routeview->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1213 case Selection::Toggle:
1214 selection->add (touched);
1216 case Selection::Set:
1217 selection->set (touched);
1219 case Selection::Extend:
1220 /* meaningless, because we're selecting everything */
1222 case Selection::Add:
1223 selection->add (touched);
1229 Editor::select_all_internal_edit (Selection::Operation)
1231 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1232 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1234 mrv->select_all_notes ();
1240 Editor::select_all (Selection::Operation op)
1242 list<Selectable *> touched;
1244 if (_internal_editing) {
1245 select_all_internal_edit (op);
1249 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1250 if ((*iter)->hidden()) {
1253 (*iter)->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1255 begin_reversible_command (_("select all"));
1257 case Selection::Add:
1258 selection->add (touched);
1260 case Selection::Toggle:
1261 selection->add (touched);
1263 case Selection::Set:
1264 selection->set (touched);
1266 case Selection::Extend:
1267 /* meaningless, because we're selecting everything */
1270 commit_reversible_command ();
1274 Editor::invert_selection_in_track ()
1276 list<Selectable *> touched;
1278 if (!clicked_routeview) {
1282 clicked_routeview->get_inverted_selectables (*selection, touched);
1283 selection->set (touched);
1287 Editor::invert_selection ()
1289 list<Selectable *> touched;
1291 if (_internal_editing) {
1292 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1293 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1295 mrv->invert_selection ();
1301 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1302 if ((*iter)->hidden()) {
1305 (*iter)->get_inverted_selectables (*selection, touched);
1308 selection->set (touched);
1311 /** @param start Start time in session frames.
1312 * @param end End time in session frames.
1313 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
1314 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
1315 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
1316 * within the region are already selected.
1319 Editor::select_all_within (framepos_t start, framepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected)
1321 list<Selectable*> found;
1323 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1325 if ((*iter)->hidden()) {
1329 (*iter)->get_selectables (start, end, top, bot, found);
1332 if (found.empty()) {
1336 if (preserve_if_selected && op != Selection::Toggle) {
1337 list<Selectable*>::iterator i = found.begin();
1338 while (i != found.end() && (*i)->get_selected()) {
1342 if (i == found.end()) {
1347 begin_reversible_command (_("select all within"));
1349 case Selection::Add:
1350 selection->add (found);
1352 case Selection::Toggle:
1353 selection->toggle (found);
1355 case Selection::Set:
1356 selection->set (found);
1358 case Selection::Extend:
1359 /* not defined yet */
1363 commit_reversible_command ();
1367 Editor::set_selection_from_region ()
1369 if (selection->regions.empty()) {
1373 selection->set (selection->regions.start(), selection->regions.end_frame());
1374 if (!Profile->get_sae()) {
1375 set_mouse_mode (Editing::MouseRange, false);
1380 Editor::set_selection_from_punch()
1384 if ((location = _session->locations()->auto_punch_location()) == 0) {
1388 set_selection_from_range (*location);
1392 Editor::set_selection_from_loop()
1396 if ((location = _session->locations()->auto_loop_location()) == 0) {
1399 set_selection_from_range (*location);
1403 Editor::set_selection_from_range (Location& loc)
1405 begin_reversible_command (_("set selection from range"));
1406 selection->set (loc.start(), loc.end());
1407 commit_reversible_command ();
1409 if (!Profile->get_sae()) {
1410 set_mouse_mode (Editing::MouseRange, false);
1415 Editor::select_all_selectables_using_time_selection ()
1417 list<Selectable *> touched;
1419 if (selection->time.empty()) {
1423 framepos_t start = selection->time[clicked_selection].start;
1424 framepos_t end = selection->time[clicked_selection].end;
1426 if (end - start < 1) {
1432 if (selection->tracks.empty()) {
1435 ts = &selection->tracks;
1438 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1439 if ((*iter)->hidden()) {
1442 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1445 begin_reversible_command (_("select all from range"));
1446 selection->set (touched);
1447 commit_reversible_command ();
1452 Editor::select_all_selectables_using_punch()
1454 Location* location = _session->locations()->auto_punch_location();
1455 list<Selectable *> touched;
1457 if (location == 0 || (location->end() - location->start() <= 1)) {
1464 if (selection->tracks.empty()) {
1467 ts = &selection->tracks;
1470 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1471 if ((*iter)->hidden()) {
1474 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1476 begin_reversible_command (_("select all from punch"));
1477 selection->set (touched);
1478 commit_reversible_command ();
1483 Editor::select_all_selectables_using_loop()
1485 Location* location = _session->locations()->auto_loop_location();
1486 list<Selectable *> touched;
1488 if (location == 0 || (location->end() - location->start() <= 1)) {
1495 if (selection->tracks.empty()) {
1498 ts = &selection->tracks;
1501 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1502 if ((*iter)->hidden()) {
1505 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1507 begin_reversible_command (_("select all from loop"));
1508 selection->set (touched);
1509 commit_reversible_command ();
1514 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1518 list<Selectable *> touched;
1521 start = cursor->current_frame;
1522 end = _session->current_end_frame();
1524 if (cursor->current_frame > 0) {
1526 end = cursor->current_frame - 1;
1532 if (_internal_editing) {
1533 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1534 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1536 mrv->select_range (start, end);
1543 begin_reversible_command (_("select all after cursor"));
1545 begin_reversible_command (_("select all before cursor"));
1550 if (selection->tracks.empty()) {
1553 ts = &selection->tracks;
1556 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1557 if ((*iter)->hidden()) {
1560 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1562 selection->set (touched);
1563 commit_reversible_command ();
1567 Editor::select_all_selectables_using_edit (bool after)
1571 list<Selectable *> touched;
1574 start = get_preferred_edit_position();
1575 end = _session->current_end_frame();
1577 if ((end = get_preferred_edit_position()) > 1) {
1585 if (_internal_editing) {
1586 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1587 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1588 mrv->select_range (start, end);
1594 begin_reversible_command (_("select all after edit"));
1596 begin_reversible_command (_("select all before edit"));
1601 if (selection->tracks.empty()) {
1604 ts = &selection->tracks;
1607 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1608 if ((*iter)->hidden()) {
1611 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1613 selection->set (touched);
1614 commit_reversible_command ();
1618 Editor::select_all_selectables_between (bool /*within*/)
1622 list<Selectable *> touched;
1624 if (!get_edit_op_range (start, end)) {
1628 if (_internal_editing) {
1629 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1630 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1631 mrv->select_range (start, end);
1638 if (selection->tracks.empty()) {
1641 ts = &selection->tracks;
1644 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1645 if ((*iter)->hidden()) {
1648 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1651 selection->set (touched);
1655 Editor::select_range_between ()
1660 if (mouse_mode == MouseRange && !selection->time.empty()) {
1661 selection->clear_time ();
1664 if (!get_edit_op_range (start, end)) {
1668 set_mouse_mode (MouseRange);
1669 selection->set (start, end);
1673 Editor::get_edit_op_range (framepos_t& start, framepos_t& end) const
1678 /* in range mode, use any existing selection */
1680 if (mouse_mode == MouseRange && !selection->time.empty()) {
1681 /* we know that these are ordered */
1682 start = selection->time.start();
1683 end = selection->time.end_frame();
1687 if (!mouse_frame (m, ignored)) {
1688 /* mouse is not in a canvas, try playhead+selected marker.
1689 this is probably most true when using menus.
1692 if (selection->markers.empty()) {
1696 start = selection->markers.front()->position();
1697 end = _session->audible_frame();
1701 switch (_edit_point) {
1702 case EditAtPlayhead:
1703 if (selection->markers.empty()) {
1704 /* use mouse + playhead */
1706 end = _session->audible_frame();
1708 /* use playhead + selected marker */
1709 start = _session->audible_frame();
1710 end = selection->markers.front()->position();
1715 /* use mouse + selected marker */
1716 if (selection->markers.empty()) {
1718 end = _session->audible_frame();
1720 start = selection->markers.front()->position();
1725 case EditAtSelectedMarker:
1726 /* use mouse + selected marker */
1727 if (selection->markers.empty()) {
1729 MessageDialog win (_("No edit range defined"),
1734 win.set_secondary_text (
1735 _("the edit point is Selected Marker\nbut there is no selected marker."));
1738 win.set_default_response (RESPONSE_CLOSE);
1739 win.set_position (Gtk::WIN_POS_MOUSE);
1744 return false; // NO RANGE
1746 start = selection->markers.front()->position();
1760 /* turn range into one delimited by start...end,
1770 Editor::deselect_all ()
1772 selection->clear ();
1776 Editor::select_range_around_region (RegionView* rv)
1780 selection->set (&rv->get_time_axis_view());
1782 selection->time.clear ();
1783 boost::shared_ptr<Region> r = rv->region ();
1784 return selection->set (r->position(), r->position() + r->length());