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
457 for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
469 Editor::get_regionview_count_from_region_list (boost::shared_ptr<Region> region)
471 int region_count = 0;
473 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
475 RouteTimeAxisView* tatv;
477 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
479 boost::shared_ptr<Playlist> pl;
480 vector<boost::shared_ptr<Region> > results;
482 boost::shared_ptr<Track> tr;
484 if ((tr = tatv->track()) == 0) {
489 if ((pl = (tr->playlist())) != 0) {
490 pl->get_region_list_equivalent_regions (region, results);
493 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
494 if ((marv = tatv->view()->find_view (*ir)) != 0) {
507 Editor::set_selected_regionview_from_click (bool press, Selection::Operation op, bool /*no_track_remove*/)
509 vector<RegionView*> all_equivalent_regions;
512 if (!clicked_regionview || !clicked_routeview) {
517 button_release_can_deselect = false;
520 if (op == Selection::Toggle || op == Selection::Set) {
524 case Selection::Toggle:
526 if (selection->selected (clicked_regionview)) {
529 /* whatever was clicked was selected already; do nothing here but allow
530 the button release to deselect it
533 button_release_can_deselect = true;
537 if (button_release_can_deselect) {
539 /* just remove this one region, but only on a permitted button release */
541 selection->remove (clicked_regionview);
544 /* no more deselect action on button release till a new press
545 finds an already selected object.
548 button_release_can_deselect = false;
556 if (selection->selected (clicked_routeview)) {
557 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
559 all_equivalent_regions.push_back (clicked_regionview);
562 /* add all the equivalent regions, but only on button press */
564 if (!all_equivalent_regions.empty()) {
568 selection->add (all_equivalent_regions);
574 if (!selection->selected (clicked_regionview)) {
575 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
576 selection->set (all_equivalent_regions);
579 /* no commit necessary: clicked on an already selected region */
589 } else if (op == Selection::Extend) {
591 list<Selectable*> results;
592 framepos_t last_frame;
593 framepos_t first_frame;
594 bool same_track = false;
596 /* 1. find the last selected regionview in the track that was clicked in */
599 first_frame = max_framepos;
601 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
602 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
604 if ((*x)->region()->last_frame() > last_frame) {
605 last_frame = (*x)->region()->last_frame();
608 if ((*x)->region()->first_frame() < first_frame) {
609 first_frame = (*x)->region()->first_frame();
618 /* 2. figure out the boundaries for our search for new objects */
620 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
622 if (last_frame < clicked_regionview->region()->first_frame()) {
623 first_frame = last_frame;
624 last_frame = clicked_regionview->region()->last_frame();
626 last_frame = first_frame;
627 first_frame = clicked_regionview->region()->first_frame();
631 case OverlapExternal:
632 if (last_frame < clicked_regionview->region()->first_frame()) {
633 first_frame = last_frame;
634 last_frame = clicked_regionview->region()->last_frame();
636 last_frame = first_frame;
637 first_frame = clicked_regionview->region()->first_frame();
641 case OverlapInternal:
642 if (last_frame < clicked_regionview->region()->first_frame()) {
643 first_frame = last_frame;
644 last_frame = clicked_regionview->region()->last_frame();
646 last_frame = first_frame;
647 first_frame = clicked_regionview->region()->first_frame();
653 /* nothing to do except add clicked region to selection, since it
654 overlaps with the existing selection in this track.
661 /* click in a track that has no regions selected, so extend vertically
662 to pick out all regions that are defined by the existing selection
667 first_frame = clicked_regionview->region()->position();
668 last_frame = clicked_regionview->region()->last_frame();
670 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
671 if ((*i)->region()->position() < first_frame) {
672 first_frame = (*i)->region()->position();
674 if ((*i)->region()->last_frame() + 1 > last_frame) {
675 last_frame = (*i)->region()->last_frame();
680 /* 2. find all the tracks we should select in */
682 set<RouteTimeAxisView*> relevant_tracks;
684 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
685 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
687 relevant_tracks.insert (r);
691 set<RouteTimeAxisView*> already_in_selection;
693 if (relevant_tracks.empty()) {
695 /* no tracks selected .. thus .. if the
696 regionview we're in isn't selected
697 (i.e. we're about to extend to it), then
698 find all tracks between the this one and
702 if (!selection->selected (clicked_regionview)) {
704 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&clicked_regionview->get_time_axis_view());
708 /* add this track to the ones we will search */
710 relevant_tracks.insert (rtv);
712 /* find the track closest to this one that
713 already a selected region.
716 RouteTimeAxisView* closest = 0;
717 int distance = INT_MAX;
718 int key = rtv->route()->order_key ("editor");
720 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
722 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
724 if (artv && artv != rtv) {
726 pair<set<RouteTimeAxisView*>::iterator,bool> result;
728 result = already_in_selection.insert (artv);
731 /* newly added to already_in_selection */
733 int d = artv->route()->order_key ("editor");
737 if (abs (d) < distance) {
747 /* now add all tracks between that one and this one */
749 int okey = closest->route()->order_key ("editor");
755 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
756 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
757 if (artv && artv != rtv) {
759 int k = artv->route()->order_key ("editor");
761 if (k >= okey && k <= key) {
763 /* in range but don't add it if
764 it already has tracks selected.
765 this avoids odd selection
766 behaviour that feels wrong.
769 if (find (already_in_selection.begin(),
770 already_in_selection.end(),
771 artv) == already_in_selection.end()) {
773 relevant_tracks.insert (artv);
783 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
784 one that was clicked.
787 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
788 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
791 /* 4. convert to a vector of regions */
793 vector<RegionView*> regions;
795 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
798 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
799 regions.push_back (arv);
803 if (!regions.empty()) {
804 selection->add (regions);
815 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
817 vector<RegionView*> all_equivalent_regions;
819 get_regions_corresponding_to (region, all_equivalent_regions);
821 if (all_equivalent_regions.empty()) {
825 begin_reversible_command (_("set selected regions"));
828 case Selection::Toggle:
829 /* XXX this is not correct */
830 selection->toggle (all_equivalent_regions);
833 selection->set (all_equivalent_regions);
835 case Selection::Extend:
836 selection->add (all_equivalent_regions);
839 selection->add (all_equivalent_regions);
843 commit_reversible_command () ;
847 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
850 boost::shared_ptr<Region> r (weak_r.lock());
856 if ((rv = sv->find_view (r)) == 0) {
860 /* don't reset the selection if its something other than
861 a single other region.
864 if (selection->regions.size() > 1) {
868 begin_reversible_command (_("set selected regions"));
872 commit_reversible_command () ;
878 Editor::track_selection_changed ()
880 switch (selection->tracks.size()) {
884 set_selected_mixer_strip (*(selection->tracks.front()));
888 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
890 bool yn = (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end());
892 (*i)->set_selected (yn);
894 TimeAxisView::Children c = (*i)->get_child_list ();
895 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
896 (*j)->set_selected (find (selection->tracks.begin(), selection->tracks.end(), j->get()) != selection->tracks.end());
900 ((mouse_mode == MouseRange) ||
901 ((mouse_mode == MouseObject) && (_join_object_range_state == JOIN_OBJECT_RANGE_OBJECT)))) {
902 (*i)->reshow_selection (selection->time);
904 (*i)->hide_selection ();
908 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
912 Editor::time_selection_changed ()
914 if (Profile->get_sae()) {
918 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
919 (*i)->hide_selection ();
922 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
923 (*i)->show_selection (selection->time);
926 if (selection->time.empty()) {
927 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
929 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
933 /** Set all region actions to have a given sensitivity */
935 Editor::sensitize_all_region_actions (bool s)
937 Glib::ListHandle<Glib::RefPtr<Action> > all = _region_actions->get_actions ();
939 for (Glib::ListHandle<Glib::RefPtr<Action> >::iterator i = all.begin(); i != all.end(); ++i) {
940 (*i)->set_sensitive (s);
943 _all_region_actions_sensitized = s;
946 /** Sensitize region-based actions based on the selection ONLY, ignoring the entered_regionview.
947 * This method should be called just before displaying a Region menu. When a Region menu is not
948 * currently being shown, all region actions are sensitized so that hotkey-triggered actions
949 * on entered_regionviews work without having to check sensitivity every time the selection or
950 * entered_regionview changes.
952 * This method also sets up toggle action state as appropriate.
955 Editor::sensitize_the_right_region_actions ()
957 if ((mouse_mode == MouseRange) || (mouse_mode != MouseObject && _join_object_range_state == JOIN_OBJECT_RANGE_RANGE)) {
958 sensitize_all_region_actions (false);
959 if (!selection->time.empty()) {
960 _region_actions->get_action("split-region")->set_sensitive (true);
965 } else if (mouse_mode != MouseObject) {
966 sensitize_all_region_actions (false);
970 /* We get here if we are in Object mode */
972 RegionSelection rs = get_regions_from_selection_and_entered ();
973 sensitize_all_region_actions (!rs.empty ());
975 _ignore_region_action = true;
977 /* Look through the regions that are selected and make notes about what we have got */
979 bool have_audio = false;
980 bool have_midi = false;
981 bool have_locked = false;
982 bool have_unlocked = false;
983 bool have_position_lock_style_audio = false;
984 bool have_position_lock_style_music = false;
985 bool have_muted = false;
986 bool have_unmuted = false;
987 bool have_opaque = false;
988 bool have_non_opaque = false;
989 bool have_not_at_natural_position = false;
990 bool have_envelope_visible = false;
991 bool have_envelope_invisible = false;
992 bool have_envelope_active = false;
993 bool have_envelope_inactive = false;
994 bool have_non_unity_scale_amplitude = false;
996 for (list<RegionView*>::const_iterator i = rs.begin(); i != rs.end(); ++i) {
998 boost::shared_ptr<Region> r = (*i)->region ();
999 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
1005 if (boost::dynamic_pointer_cast<MidiRegion> (r)) {
1012 have_unlocked = true;
1015 if (r->position_lock_style() == MusicTime) {
1016 have_position_lock_style_music = true;
1018 have_position_lock_style_audio = true;
1024 have_unmuted = true;
1030 have_non_opaque = true;
1033 if (!r->at_natural_position()) {
1034 have_not_at_natural_position = true;
1038 /* its a bit unfortunate that "envelope visible" is a view-only
1039 property. we have to find the regionview to able to check
1040 its current setting.
1043 have_envelope_invisible = true;
1046 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
1047 if (arv && arv->envelope_visible()) {
1048 have_envelope_visible = true;
1052 if (ar->envelope_active()) {
1053 have_envelope_active = true;
1055 have_envelope_inactive = true;
1058 if (ar->scale_amplitude() != 1) {
1059 have_non_unity_scale_amplitude = true;
1064 if (rs.size() > 1) {
1065 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1066 _region_actions->get_action("show-region-properties")->set_sensitive (false);
1067 _region_actions->get_action("rename-region")->set_sensitive (false);
1068 } else if (rs.size() == 1) {
1069 _region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
1070 _region_actions->get_action("close-region-gaps")->set_sensitive (false);
1074 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1075 _region_actions->get_action("quantize-region")->set_sensitive (false);
1076 _region_actions->get_action("fork-region")->set_sensitive (false);
1079 if (_edit_point == EditAtMouse) {
1080 _region_actions->get_action("set-region-sync-position")->set_sensitive (false);
1081 _region_actions->get_action("trim-front")->set_sensitive (false);
1082 _region_actions->get_action("trim-back")->set_sensitive (false);
1083 _region_actions->get_action("split-region")->set_sensitive (false);
1084 _region_actions->get_action("place-transient")->set_sensitive (false);
1089 if (have_envelope_visible && !have_envelope_invisible) {
1090 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-visible"))->set_active ();
1091 } else if (have_envelope_visible && have_envelope_invisible) {
1092 // _region_actions->get_action("toggle-region-gain-envelope-visible")->set_inconsistent ();
1095 if (have_envelope_active && !have_envelope_inactive) {
1096 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active ();
1097 } else if (have_envelope_active && have_envelope_inactive) {
1098 // _region_actions->get_action("toggle-region-gain-envelope-active")->set_inconsistent ();
1103 _region_actions->get_action("analyze-region")->set_sensitive (false);
1104 _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
1105 _region_actions->get_action("toggle-region-gain-envelope-visible")->set_sensitive (false);
1106 _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
1110 if (!have_non_unity_scale_amplitude || !have_audio) {
1111 _region_actions->get_action("reset-region-scale-amplitude")->set_sensitive (false);
1114 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"))->set_active (have_locked && !have_unlocked);
1115 if (have_locked && have_unlocked) {
1116 // _region_actions->get_action("toggle-region-lock")->set_inconsistent ();
1119 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);
1121 if (have_position_lock_style_music && have_position_lock_style_audio) {
1122 // _region_actions->get_action("toggle-region-lock-style")->set_inconsistent ();
1125 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"))->set_active (have_muted && !have_unmuted);
1126 if (have_muted && have_unmuted) {
1127 // _region_actions->get_action("toggle-region-mute")->set_inconsistent ();
1130 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"))->set_active (have_opaque && !have_non_opaque);
1131 if (have_opaque && have_non_opaque) {
1132 // _region_actions->get_action("toggle-opaque-region")->set_inconsistent ();
1135 if (!have_not_at_natural_position) {
1136 _region_actions->get_action("naturalize-region")->set_sensitive (false);
1139 /* XXX: should also check that there is a track of the appropriate type for the selected region */
1140 if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
1141 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (false);
1143 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (true);
1146 _ignore_region_action = false;
1148 _all_region_actions_sensitized = false;
1153 Editor::region_selection_changed ()
1155 _regions->block_change_connection (true);
1156 editor_regions_selection_changed_connection.block(true);
1158 if (_region_selection_change_updates_region_list) {
1159 _regions->unselect_all ();
1162 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1163 (*i)->set_selected_regionviews (selection->regions);
1166 if (_region_selection_change_updates_region_list) {
1167 _regions->set_selected (selection->regions);
1170 _regions->block_change_connection (false);
1171 editor_regions_selection_changed_connection.block(false);
1173 if (!_all_region_actions_sensitized) {
1174 /* This selection change might have changed what region actions
1175 are allowed, so sensitize them all in case a key is pressed.
1177 sensitize_all_region_actions (true);
1182 Editor::point_selection_changed ()
1184 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1185 (*i)->set_selected_points (selection->points);
1190 Editor::select_all_in_track (Selection::Operation op)
1192 list<Selectable *> touched;
1194 if (!clicked_routeview) {
1198 clicked_routeview->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1201 case Selection::Toggle:
1202 selection->add (touched);
1204 case Selection::Set:
1205 selection->set (touched);
1207 case Selection::Extend:
1208 /* meaningless, because we're selecting everything */
1210 case Selection::Add:
1211 selection->add (touched);
1217 Editor::select_all_internal_edit (Selection::Operation op)
1219 /* currently limited to MIDI only */
1221 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1222 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1224 mrv->select_all_notes ();
1230 Editor::select_all (Selection::Operation op)
1232 list<Selectable *> touched;
1234 if (_internal_editing) {
1235 select_all_internal_edit (op);
1239 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1240 if ((*iter)->hidden()) {
1243 (*iter)->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1245 begin_reversible_command (_("select all"));
1247 case Selection::Add:
1248 selection->add (touched);
1250 case Selection::Toggle:
1251 selection->add (touched);
1253 case Selection::Set:
1254 selection->set (touched);
1256 case Selection::Extend:
1257 /* meaningless, because we're selecting everything */
1260 commit_reversible_command ();
1263 Editor::invert_selection_in_track ()
1265 list<Selectable *> touched;
1267 if (!clicked_routeview) {
1271 clicked_routeview->get_inverted_selectables (*selection, touched);
1272 selection->set (touched);
1276 Editor::invert_selection ()
1278 list<Selectable *> touched;
1280 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1281 if ((*iter)->hidden()) {
1284 (*iter)->get_inverted_selectables (*selection, touched);
1287 selection->set (touched);
1290 /** @param start Start time in session frames.
1291 * @param end End time in session frames.
1292 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
1293 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
1294 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
1295 * within the region are already selected.
1298 Editor::select_all_within (
1299 framepos_t start, framepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected
1302 list<Selectable*> found;
1304 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1306 if ((*iter)->hidden()) {
1310 (*iter)->get_selectables (start, end, top, bot, found);
1313 if (found.empty()) {
1317 if (preserve_if_selected && op != Selection::Toggle) {
1318 list<Selectable*>::iterator i = found.begin();
1319 while (i != found.end() && (*i)->get_selected()) {
1323 if (i == found.end()) {
1328 begin_reversible_command (_("select all within"));
1330 case Selection::Add:
1331 selection->add (found);
1333 case Selection::Toggle:
1334 selection->toggle (found);
1336 case Selection::Set:
1337 selection->set (found);
1339 case Selection::Extend:
1340 /* not defined yet */
1344 commit_reversible_command ();
1348 Editor::set_selection_from_region ()
1350 if (selection->regions.empty()) {
1354 selection->set (selection->regions.start(), selection->regions.end_frame());
1355 if (!Profile->get_sae()) {
1356 set_mouse_mode (Editing::MouseRange, false);
1361 Editor::set_selection_from_punch()
1365 if ((location = _session->locations()->auto_punch_location()) == 0) {
1369 set_selection_from_range (*location);
1373 Editor::set_selection_from_loop()
1377 if ((location = _session->locations()->auto_loop_location()) == 0) {
1380 set_selection_from_range (*location);
1384 Editor::set_selection_from_range (Location& loc)
1386 begin_reversible_command (_("set selection from range"));
1387 selection->set (loc.start(), loc.end());
1388 commit_reversible_command ();
1390 if (!Profile->get_sae()) {
1391 set_mouse_mode (Editing::MouseRange, false);
1396 Editor::select_all_selectables_using_time_selection ()
1398 list<Selectable *> touched;
1400 if (selection->time.empty()) {
1404 framepos_t start = selection->time[clicked_selection].start;
1405 framepos_t end = selection->time[clicked_selection].end;
1407 if (end - start < 1) {
1413 if (selection->tracks.empty()) {
1416 ts = &selection->tracks;
1419 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1420 if ((*iter)->hidden()) {
1423 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1426 begin_reversible_command (_("select all from range"));
1427 selection->set (touched);
1428 commit_reversible_command ();
1433 Editor::select_all_selectables_using_punch()
1435 Location* location = _session->locations()->auto_punch_location();
1436 list<Selectable *> touched;
1438 if (location == 0 || (location->end() - location->start() <= 1)) {
1445 if (selection->tracks.empty()) {
1448 ts = &selection->tracks;
1451 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1452 if ((*iter)->hidden()) {
1455 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1457 begin_reversible_command (_("select all from punch"));
1458 selection->set (touched);
1459 commit_reversible_command ();
1464 Editor::select_all_selectables_using_loop()
1466 Location* location = _session->locations()->auto_loop_location();
1467 list<Selectable *> touched;
1469 if (location == 0 || (location->end() - location->start() <= 1)) {
1476 if (selection->tracks.empty()) {
1479 ts = &selection->tracks;
1482 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1483 if ((*iter)->hidden()) {
1486 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1488 begin_reversible_command (_("select all from loop"));
1489 selection->set (touched);
1490 commit_reversible_command ();
1495 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1499 list<Selectable *> touched;
1502 begin_reversible_command (_("select all after cursor"));
1503 start = cursor->current_frame;
1504 end = _session->current_end_frame();
1506 if (cursor->current_frame > 0) {
1507 begin_reversible_command (_("select all before cursor"));
1509 end = cursor->current_frame - 1;
1518 if (selection->tracks.empty()) {
1521 ts = &selection->tracks;
1524 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1525 if ((*iter)->hidden()) {
1528 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1530 selection->set (touched);
1531 commit_reversible_command ();
1535 Editor::select_all_selectables_using_edit (bool after)
1539 list<Selectable *> touched;
1542 begin_reversible_command (_("select all after edit"));
1543 start = get_preferred_edit_position();
1544 end = _session->current_end_frame();
1546 if ((end = get_preferred_edit_position()) > 1) {
1547 begin_reversible_command (_("select all before edit"));
1558 if (selection->tracks.empty()) {
1561 ts = &selection->tracks;
1564 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1565 if ((*iter)->hidden()) {
1568 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1570 selection->set (touched);
1571 commit_reversible_command ();
1575 Editor::select_all_selectables_between (bool /*within*/)
1579 list<Selectable *> touched;
1581 if (!get_edit_op_range (start, end)) {
1587 if (selection->tracks.empty()) {
1590 ts = &selection->tracks;
1593 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1594 if ((*iter)->hidden()) {
1597 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1600 selection->set (touched);
1604 Editor::select_range_between ()
1609 if (mouse_mode == MouseRange && !selection->time.empty()) {
1610 selection->clear_time ();
1613 if (!get_edit_op_range (start, end)) {
1617 set_mouse_mode (MouseRange);
1618 selection->set (start, end);
1622 Editor::get_edit_op_range (framepos_t& start, framepos_t& end) const
1627 /* in range mode, use any existing selection */
1629 if (mouse_mode == MouseRange && !selection->time.empty()) {
1630 /* we know that these are ordered */
1631 start = selection->time.start();
1632 end = selection->time.end_frame();
1636 if (!mouse_frame (m, ignored)) {
1637 /* mouse is not in a canvas, try playhead+selected marker.
1638 this is probably most true when using menus.
1641 if (selection->markers.empty()) {
1645 start = selection->markers.front()->position();
1646 end = _session->audible_frame();
1650 switch (_edit_point) {
1651 case EditAtPlayhead:
1652 if (selection->markers.empty()) {
1653 /* use mouse + playhead */
1655 end = _session->audible_frame();
1657 /* use playhead + selected marker */
1658 start = _session->audible_frame();
1659 end = selection->markers.front()->position();
1664 /* use mouse + selected marker */
1665 if (selection->markers.empty()) {
1667 end = _session->audible_frame();
1669 start = selection->markers.front()->position();
1674 case EditAtSelectedMarker:
1675 /* use mouse + selected marker */
1676 if (selection->markers.empty()) {
1678 MessageDialog win (_("No edit range defined"),
1683 win.set_secondary_text (
1684 _("the edit point is Selected Marker\nbut there is no selected marker."));
1687 win.set_default_response (RESPONSE_CLOSE);
1688 win.set_position (Gtk::WIN_POS_MOUSE);
1693 return false; // NO RANGE
1695 start = selection->markers.front()->position();
1709 /* turn range into one delimited by start...end,
1719 Editor::deselect_all ()
1721 selection->clear ();
1725 Editor::select_range_around_region (RegionView* rv)
1729 selection->set (&rv->get_time_axis_view());
1731 selection->time.clear ();
1732 boost::shared_ptr<Region> r = rv->region ();
1733 return selection->set (r->position(), r->position() + r->length());