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"
44 using namespace ARDOUR;
48 using namespace Gtkmm2ext;
49 using namespace Editing;
51 struct TrackViewByPositionSorter
53 bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
54 return a->y_position() < b->y_position();
59 Editor::extend_selection_to_track (TimeAxisView& view)
61 if (selection->selected (&view)) {
62 /* already selected, do nothing */
66 if (selection->tracks.empty()) {
68 if (!selection->selected (&view)) {
69 selection->set (&view);
76 /* something is already selected, so figure out which range of things to add */
78 TrackViewList to_be_added;
79 TrackViewList sorted = track_views;
80 TrackViewByPositionSorter cmp;
81 bool passed_clicked = false;
86 if (!selection->selected (&view)) {
87 to_be_added.push_back (&view);
90 /* figure out if we should go forward or backwards */
92 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
95 passed_clicked = true;
98 if (selection->selected (*i)) {
108 passed_clicked = false;
112 for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
115 passed_clicked = true;
119 if (passed_clicked) {
120 if ((*i)->hidden()) {
123 if (selection->selected (*i)) {
125 } else if (!(*i)->hidden()) {
126 to_be_added.push_back (*i);
133 for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
136 passed_clicked = true;
140 if (passed_clicked) {
142 if ((*r)->hidden()) {
146 if (selection->selected (*r)) {
148 } else if (!(*r)->hidden()) {
149 to_be_added.push_back (*r);
155 if (!to_be_added.empty()) {
156 selection->add (to_be_added);
164 Editor::select_all_tracks ()
166 TrackViewList visible_views;
167 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
168 if ((*i)->marked_for_display()) {
169 visible_views.push_back (*i);
172 selection->set (visible_views);
175 /** Select clicked_axisview, unless there are no currently selected
176 * tracks, in which case nothing will happen unless `force' is true.
179 Editor::set_selected_track_as_side_effect (Selection::Operation op, bool /*force*/)
181 if (!clicked_axisview) {
186 if (!clicked_routeview) {
190 bool had_tracks = !selection->tracks.empty();
191 RouteGroup* group = clicked_routeview->route()->route_group();
192 RouteGroup& arg (_session->all_route_group());
195 case Selection::Toggle:
196 if (selection->selected (clicked_axisview)) {
197 if (arg.is_select() && arg.is_active()) {
198 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
199 selection->remove(*i);
201 } else if (group && group->is_active()) {
202 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
203 if ((*i)->route_group() == group)
204 selection->remove(*i);
207 selection->remove (clicked_axisview);
210 if (arg.is_select() && arg.is_active()) {
211 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
214 } else if (group && group->is_active()) {
215 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
216 if ( (*i)->route_group() == group)
220 selection->add (clicked_axisview);
226 if (!had_tracks && arg.is_select() && arg.is_active()) {
227 /* nothing was selected already, and all group is active etc. so use
230 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
233 } else if (group && group->is_active()) {
234 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
235 if ((*i)->route_group() == group)
239 selection->add (clicked_axisview);
245 if (!had_tracks && arg.is_select() && arg.is_active()) {
246 /* nothing was selected already, and all group is active etc. so use
249 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
252 } else if (group && group->is_active()) {
253 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
254 if ((*i)->route_group() == group)
258 selection->set (clicked_axisview);
262 case Selection::Extend:
264 cerr << ("Editor::set_selected_track_as_side_effect case Selection::Add not yet implemented\n");
268 #else // the older version
270 if (!selection->tracks.empty()) {
271 if (!selection->selected (clicked_axisview)) {
272 selection->add (clicked_axisview);
276 selection->set (clicked_axisview);
282 Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no_remove)
285 case Selection::Toggle:
286 if (selection->selected (&view)) {
288 selection->remove (&view);
291 selection->add (&view);
296 if (!selection->selected (&view)) {
297 selection->add (&view);
302 selection->set (&view);
305 case Selection::Extend:
306 extend_selection_to_track (view);
312 Editor::set_selected_track_from_click (bool press, Selection::Operation op, bool no_remove)
314 if (!clicked_routeview) {
322 set_selected_track (*clicked_routeview, op, no_remove);
326 Editor::set_selected_control_point_from_click (Selection::Operation op, bool /*no_remove*/)
328 if (!clicked_control_point) {
334 selection->set (clicked_control_point);
337 selection->add (clicked_control_point);
339 case Selection::Toggle:
340 selection->toggle (clicked_control_point);
342 case Selection::Extend:
351 Editor::get_onscreen_tracks (TrackViewList& tvl)
353 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
354 if ((*i)->y_position() < _canvas_height) {
360 /** Call a slot for a given `basis' track and also for any track that is in the same
361 * active route group with a particular set of properties.
363 * @param sl Slot to call.
364 * @param basis Basis track.
365 * @param prop Properties that active edit groups must share to be included in the map.
369 Editor::mapover_tracks (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
371 RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
373 if (route_basis == 0) {
377 set<RouteTimeAxisView*> tracks;
378 tracks.insert (route_basis);
380 RouteGroup* group = route_basis->route()->route_group();
382 if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id) ) {
384 /* the basis is a member of an active route group, with the appropriate
385 properties; find other members */
387 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
388 RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
389 if (v && v->route()->route_group() == group) {
396 uint32_t const sz = tracks.size ();
398 for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
404 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
406 boost::shared_ptr<Playlist> pl;
407 vector<boost::shared_ptr<Region> > results;
409 boost::shared_ptr<Track> tr;
411 if ((tr = tv.track()) == 0) {
416 if (&tv == &basis->get_time_axis_view()) {
417 /* looking in same track as the original */
421 if ((pl = tr->playlist()) != 0) {
422 pl->get_equivalent_regions (basis->region(), results);
425 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
426 if ((marv = tv.view()->find_view (*ir)) != 0) {
427 all_equivs->push_back (marv);
433 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, PBD::PropertyID property) const
435 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_time_axis_view(), property);
437 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
439 equivalent_regions.push_back (basis);
443 Editor::get_equivalent_regions (RegionSelection & basis, PBD::PropertyID prop) const
445 RegionSelection equivalent;
447 for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
449 vector<RegionView*> eq;
452 sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
453 &(*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:
525 if (selection->selected (clicked_regionview)) {
528 /* whatever was clicked was selected already; do nothing here but allow
529 the button release to deselect it
532 button_release_can_deselect = true;
536 if (button_release_can_deselect) {
538 /* just remove this one region, but only on a permitted button release */
540 selection->remove (clicked_regionview);
543 /* no more deselect action on button release till a new press
544 finds an already selected object.
547 button_release_can_deselect = false;
555 if (selection->selected (clicked_routeview)) {
556 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
558 all_equivalent_regions.push_back (clicked_regionview);
561 /* add all the equivalent regions, but only on button press */
563 if (!all_equivalent_regions.empty()) {
567 selection->add (all_equivalent_regions);
573 if (!selection->selected (clicked_regionview)) {
574 get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
575 selection->set (all_equivalent_regions);
578 /* no commit necessary: clicked on an already selected region */
588 } else if (op == Selection::Extend) {
590 list<Selectable*> results;
591 framepos_t last_frame;
592 framepos_t first_frame;
593 bool same_track = false;
595 /* 1. find the last selected regionview in the track that was clicked in */
598 first_frame = max_framepos;
600 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
601 if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
603 if ((*x)->region()->last_frame() > last_frame) {
604 last_frame = (*x)->region()->last_frame();
607 if ((*x)->region()->first_frame() < first_frame) {
608 first_frame = (*x)->region()->first_frame();
617 /* 2. figure out the boundaries for our search for new objects */
619 switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
621 if (last_frame < clicked_regionview->region()->first_frame()) {
622 first_frame = last_frame;
623 last_frame = clicked_regionview->region()->last_frame();
625 last_frame = first_frame;
626 first_frame = clicked_regionview->region()->first_frame();
630 case OverlapExternal:
631 if (last_frame < clicked_regionview->region()->first_frame()) {
632 first_frame = last_frame;
633 last_frame = clicked_regionview->region()->last_frame();
635 last_frame = first_frame;
636 first_frame = clicked_regionview->region()->first_frame();
640 case OverlapInternal:
641 if (last_frame < clicked_regionview->region()->first_frame()) {
642 first_frame = last_frame;
643 last_frame = clicked_regionview->region()->last_frame();
645 last_frame = first_frame;
646 first_frame = clicked_regionview->region()->first_frame();
652 /* nothing to do except add clicked region to selection, since it
653 overlaps with the existing selection in this track.
660 /* click in a track that has no regions selected, so extend vertically
661 to pick out all regions that are defined by the existing selection
666 first_frame = clicked_regionview->region()->position();
667 last_frame = clicked_regionview->region()->last_frame();
669 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
670 if ((*i)->region()->position() < first_frame) {
671 first_frame = (*i)->region()->position();
673 if ((*i)->region()->last_frame() + 1 > last_frame) {
674 last_frame = (*i)->region()->last_frame();
679 /* 2. find all the tracks we should select in */
681 set<RouteTimeAxisView*> relevant_tracks;
683 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
684 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
686 relevant_tracks.insert (r);
690 set<RouteTimeAxisView*> already_in_selection;
692 if (relevant_tracks.empty()) {
694 /* no tracks selected .. thus .. if the
695 regionview we're in isn't selected
696 (i.e. we're about to extend to it), then
697 find all tracks between the this one and
701 if (!selection->selected (clicked_regionview)) {
703 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&clicked_regionview->get_time_axis_view());
707 /* add this track to the ones we will search */
709 relevant_tracks.insert (rtv);
711 /* find the track closest to this one that
712 already a selected region.
715 RouteTimeAxisView* closest = 0;
716 int distance = INT_MAX;
717 int key = rtv->route()->order_key ("editor");
719 for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
721 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
723 if (artv && artv != rtv) {
725 pair<set<RouteTimeAxisView*>::iterator,bool> result;
727 result = already_in_selection.insert (artv);
730 /* newly added to already_in_selection */
732 int d = artv->route()->order_key ("editor");
736 if (abs (d) < distance) {
746 /* now add all tracks between that one and this one */
748 int okey = closest->route()->order_key ("editor");
754 for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
755 RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
756 if (artv && artv != rtv) {
758 int k = artv->route()->order_key ("editor");
760 if (k >= okey && k <= key) {
762 /* in range but don't add it if
763 it already has tracks selected.
764 this avoids odd selection
765 behaviour that feels wrong.
768 if (find (already_in_selection.begin(),
769 already_in_selection.end(),
770 artv) == already_in_selection.end()) {
772 relevant_tracks.insert (artv);
782 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
783 one that was clicked.
786 for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
787 (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
790 /* 4. convert to a vector of regions */
792 vector<RegionView*> regions;
794 for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
797 if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
798 regions.push_back (arv);
802 if (!regions.empty()) {
803 selection->add (regions);
814 Editor::set_selected_regionview_from_region_list (boost::shared_ptr<Region> region, Selection::Operation op)
816 vector<RegionView*> all_equivalent_regions;
818 get_regions_corresponding_to (region, all_equivalent_regions);
820 if (all_equivalent_regions.empty()) {
824 begin_reversible_command (_("set selected regions"));
827 case Selection::Toggle:
828 /* XXX this is not correct */
829 selection->toggle (all_equivalent_regions);
832 selection->set (all_equivalent_regions);
834 case Selection::Extend:
835 selection->add (all_equivalent_regions);
838 selection->add (all_equivalent_regions);
842 commit_reversible_command () ;
846 Editor::set_selected_regionview_from_map_event (GdkEventAny* /*ev*/, StreamView* sv, boost::weak_ptr<Region> weak_r)
849 boost::shared_ptr<Region> r (weak_r.lock());
855 if ((rv = sv->find_view (r)) == 0) {
859 /* don't reset the selection if its something other than
860 a single other region.
863 if (selection->regions.size() > 1) {
867 begin_reversible_command (_("set selected regions"));
871 commit_reversible_command () ;
877 Editor::track_selection_changed ()
879 switch (selection->tracks.size()) {
883 set_selected_mixer_strip (*(selection->tracks.front()));
887 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
889 bool yn = (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end());
891 (*i)->set_selected (yn);
893 TimeAxisView::Children c = (*i)->get_child_list ();
894 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
895 (*j)->set_selected (find (selection->tracks.begin(), selection->tracks.end(), j->get()) != selection->tracks.end());
899 ((mouse_mode == MouseRange) ||
900 ((mouse_mode == MouseObject) && (_join_object_range_state == JOIN_OBJECT_RANGE_OBJECT)))) {
901 (*i)->reshow_selection (selection->time);
903 (*i)->hide_selection ();
907 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
911 Editor::time_selection_changed ()
913 if (Profile->get_sae()) {
917 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
918 (*i)->hide_selection ();
921 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
922 (*i)->show_selection (selection->time);
925 if (selection->time.empty()) {
926 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, false);
928 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions, true);
932 /** Set all region actions to have a given sensitivity */
934 Editor::sensitize_all_region_actions (bool s)
936 Glib::ListHandle<Glib::RefPtr<Action> > all = _region_actions->get_actions ();
938 for (Glib::ListHandle<Glib::RefPtr<Action> >::iterator i = all.begin(); i != all.end(); ++i) {
939 (*i)->set_sensitive (s);
942 _all_region_actions_sensitized = s;
945 /** Sensitize region-based actions based on the selection ONLY, ignoring the entered_regionview.
946 * This method should be called just before displaying a Region menu. When a Region menu is not
947 * currently being shown, all region actions are sensitized so that hotkey-triggered actions
948 * on entered_regionviews work without having to check sensitivity every time the selection or
949 * entered_regionview changes.
951 * This method also sets up toggle action state as appropriate.
954 Editor::sensitize_the_right_region_actions ()
956 if ((mouse_mode == MouseRange) || (mouse_mode != MouseObject && _join_object_range_state == JOIN_OBJECT_RANGE_RANGE)) {
957 sensitize_all_region_actions (false);
958 if (!selection->time.empty()) {
959 _region_actions->get_action("split-region")->set_sensitive (true);
964 } else if (mouse_mode != MouseObject) {
965 sensitize_all_region_actions (false);
969 /* We get here if we are in Object mode */
971 RegionSelection rs = get_regions_from_selection_and_entered ();
972 sensitize_all_region_actions (!rs.empty ());
974 _ignore_region_action = true;
976 /* Look through the regions that are selected and make notes about what we have got */
978 bool have_audio = false;
979 bool have_midi = false;
980 bool have_locked = false;
981 bool have_unlocked = false;
982 bool have_position_lock_style_audio = false;
983 bool have_position_lock_style_music = false;
984 bool have_muted = false;
985 bool have_unmuted = false;
986 bool have_opaque = false;
987 bool have_non_opaque = false;
988 bool have_not_at_natural_position = false;
989 bool have_envelope_visible = false;
990 bool have_envelope_invisible = false;
991 bool have_envelope_active = false;
992 bool have_envelope_inactive = false;
993 bool have_non_unity_scale_amplitude = false;
995 for (list<RegionView*>::const_iterator i = rs.begin(); i != rs.end(); ++i) {
997 boost::shared_ptr<Region> r = (*i)->region ();
998 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
1004 if (boost::dynamic_pointer_cast<MidiRegion> (r)) {
1011 have_unlocked = true;
1014 if (r->position_lock_style() == MusicTime) {
1015 have_position_lock_style_music = true;
1017 have_position_lock_style_audio = true;
1023 have_unmuted = true;
1029 have_non_opaque = true;
1032 if (!r->at_natural_position()) {
1033 have_not_at_natural_position = true;
1037 /* its a bit unfortunate that "envelope visible" is a view-only
1038 property. we have to find the regionview to able to check
1039 its current setting.
1042 have_envelope_invisible = true;
1045 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
1046 if (arv && arv->envelope_visible()) {
1047 have_envelope_visible = true;
1051 if (ar->envelope_active()) {
1052 have_envelope_active = true;
1054 have_envelope_inactive = true;
1057 if (ar->scale_amplitude() != 1) {
1058 have_non_unity_scale_amplitude = true;
1063 if (rs.size() > 1) {
1064 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1065 _region_actions->get_action("show-region-properties")->set_sensitive (false);
1066 _region_actions->get_action("rename-region")->set_sensitive (false);
1067 } else if (rs.size() == 1) {
1068 _region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
1069 _region_actions->get_action("close-region-gaps")->set_sensitive (false);
1073 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1074 _region_actions->get_action("quantize-region")->set_sensitive (false);
1075 _region_actions->get_action("fork-region")->set_sensitive (false);
1078 if (_edit_point == EditAtMouse) {
1079 _region_actions->get_action("set-region-sync-position")->set_sensitive (false);
1080 _region_actions->get_action("trim-front")->set_sensitive (false);
1081 _region_actions->get_action("trim-back")->set_sensitive (false);
1082 _region_actions->get_action("split-region")->set_sensitive (false);
1083 _region_actions->get_action("place-transient")->set_sensitive (false);
1088 if (have_envelope_visible && !have_envelope_invisible) {
1089 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-visible"))->set_active ();
1090 } else if (have_envelope_visible && have_envelope_invisible) {
1091 // _region_actions->get_action("toggle-region-gain-envelope-visible")->set_inconsistent ();
1094 if (have_envelope_active && !have_envelope_inactive) {
1095 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active ();
1096 } else if (have_envelope_active && have_envelope_inactive) {
1097 // _region_actions->get_action("toggle-region-gain-envelope-active")->set_inconsistent ();
1102 _region_actions->get_action("analyze-region")->set_sensitive (false);
1103 _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
1104 _region_actions->get_action("toggle-region-gain-envelope-visible")->set_sensitive (false);
1105 _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
1109 if (!have_non_unity_scale_amplitude || !have_audio) {
1110 _region_actions->get_action("reset-region-scale-amplitude")->set_sensitive (false);
1113 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"))->set_active (have_locked && !have_unlocked);
1114 if (have_locked && have_unlocked) {
1115 // _region_actions->get_action("toggle-region-lock")->set_inconsistent ();
1118 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);
1120 if (have_position_lock_style_music && have_position_lock_style_audio) {
1121 // _region_actions->get_action("toggle-region-lock-style")->set_inconsistent ();
1124 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"))->set_active (have_muted && !have_unmuted);
1125 if (have_muted && have_unmuted) {
1126 // _region_actions->get_action("toggle-region-mute")->set_inconsistent ();
1129 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"))->set_active (have_opaque && !have_non_opaque);
1130 if (have_opaque && have_non_opaque) {
1131 // _region_actions->get_action("toggle-opaque-region")->set_inconsistent ();
1134 if (!have_not_at_natural_position) {
1135 _region_actions->get_action("naturalize-region")->set_sensitive (false);
1138 /* XXX: should also check that there is a track of the appropriate type for the selected region */
1139 if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
1140 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (false);
1142 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (true);
1145 _ignore_region_action = false;
1147 _all_region_actions_sensitized = false;
1152 Editor::region_selection_changed ()
1154 _regions->block_change_connection (true);
1155 editor_regions_selection_changed_connection.block(true);
1157 if (_region_selection_change_updates_region_list) {
1158 _regions->unselect_all ();
1161 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1162 (*i)->set_selected_regionviews (selection->regions);
1165 if (_region_selection_change_updates_region_list) {
1166 _regions->set_selected (selection->regions);
1169 _regions->block_change_connection (false);
1170 editor_regions_selection_changed_connection.block(false);
1172 if (!_all_region_actions_sensitized) {
1173 /* This selection change might have changed what region actions
1174 are allowed, so sensitize them all in case a key is pressed.
1176 sensitize_all_region_actions (true);
1181 Editor::point_selection_changed ()
1183 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1184 (*i)->set_selected_points (selection->points);
1189 Editor::select_all_in_track (Selection::Operation op)
1191 list<Selectable *> touched;
1193 if (!clicked_routeview) {
1197 clicked_routeview->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1200 case Selection::Toggle:
1201 selection->add (touched);
1203 case Selection::Set:
1204 selection->set (touched);
1206 case Selection::Extend:
1207 /* meaningless, because we're selecting everything */
1209 case Selection::Add:
1210 selection->add (touched);
1216 Editor::select_all (Selection::Operation op)
1218 list<Selectable *> touched;
1220 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1221 if ((*iter)->hidden()) {
1224 (*iter)->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1226 begin_reversible_command (_("select all"));
1228 case Selection::Add:
1229 selection->add (touched);
1231 case Selection::Toggle:
1232 selection->add (touched);
1234 case Selection::Set:
1235 selection->set (touched);
1237 case Selection::Extend:
1238 /* meaningless, because we're selecting everything */
1241 commit_reversible_command ();
1244 Editor::invert_selection_in_track ()
1246 list<Selectable *> touched;
1248 if (!clicked_routeview) {
1252 clicked_routeview->get_inverted_selectables (*selection, touched);
1253 selection->set (touched);
1257 Editor::invert_selection ()
1259 list<Selectable *> touched;
1261 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1262 if ((*iter)->hidden()) {
1265 (*iter)->get_inverted_selectables (*selection, touched);
1268 selection->set (touched);
1271 /** @param start Start time in session frames.
1272 * @param end End time in session frames.
1273 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
1274 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
1275 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
1276 * within the region are already selected.
1279 Editor::select_all_within (
1280 framepos_t start, framepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected
1283 list<Selectable*> found;
1285 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1287 if ((*iter)->hidden()) {
1291 (*iter)->get_selectables (start, end, top, bot, found);
1294 if (found.empty()) {
1298 if (preserve_if_selected && op != Selection::Toggle) {
1299 list<Selectable*>::iterator i = found.begin();
1300 while (i != found.end() && (*i)->get_selected()) {
1304 if (i == found.end()) {
1309 begin_reversible_command (_("select all within"));
1311 case Selection::Add:
1312 selection->add (found);
1314 case Selection::Toggle:
1315 selection->toggle (found);
1317 case Selection::Set:
1318 selection->set (found);
1320 case Selection::Extend:
1321 /* not defined yet */
1325 commit_reversible_command ();
1327 return !found.empty();
1331 Editor::set_selection_from_region ()
1333 if (selection->regions.empty()) {
1337 selection->set (selection->regions.start(), selection->regions.end_frame());
1338 if (!Profile->get_sae()) {
1339 set_mouse_mode (Editing::MouseRange, false);
1344 Editor::set_selection_from_punch()
1348 if ((location = _session->locations()->auto_punch_location()) == 0) {
1352 set_selection_from_range (*location);
1356 Editor::set_selection_from_loop()
1360 if ((location = _session->locations()->auto_loop_location()) == 0) {
1363 set_selection_from_range (*location);
1367 Editor::set_selection_from_range (Location& loc)
1369 begin_reversible_command (_("set selection from range"));
1370 selection->set (loc.start(), loc.end());
1371 commit_reversible_command ();
1373 if (!Profile->get_sae()) {
1374 set_mouse_mode (Editing::MouseRange, false);
1379 Editor::select_all_selectables_using_time_selection ()
1381 list<Selectable *> touched;
1383 if (selection->time.empty()) {
1387 framepos_t start = selection->time[clicked_selection].start;
1388 framepos_t end = selection->time[clicked_selection].end;
1390 if (end - start < 1) {
1396 if (selection->tracks.empty()) {
1399 ts = &selection->tracks;
1402 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1403 if ((*iter)->hidden()) {
1406 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1409 begin_reversible_command (_("select all from range"));
1410 selection->set (touched);
1411 commit_reversible_command ();
1416 Editor::select_all_selectables_using_punch()
1418 Location* location = _session->locations()->auto_punch_location();
1419 list<Selectable *> touched;
1421 if (location == 0 || (location->end() - location->start() <= 1)) {
1428 if (selection->tracks.empty()) {
1431 ts = &selection->tracks;
1434 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1435 if ((*iter)->hidden()) {
1438 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1440 begin_reversible_command (_("select all from punch"));
1441 selection->set (touched);
1442 commit_reversible_command ();
1447 Editor::select_all_selectables_using_loop()
1449 Location* location = _session->locations()->auto_loop_location();
1450 list<Selectable *> touched;
1452 if (location == 0 || (location->end() - location->start() <= 1)) {
1459 if (selection->tracks.empty()) {
1462 ts = &selection->tracks;
1465 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1466 if ((*iter)->hidden()) {
1469 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1471 begin_reversible_command (_("select all from loop"));
1472 selection->set (touched);
1473 commit_reversible_command ();
1478 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1482 list<Selectable *> touched;
1485 begin_reversible_command (_("select all after cursor"));
1486 start = cursor->current_frame;
1487 end = _session->current_end_frame();
1489 if (cursor->current_frame > 0) {
1490 begin_reversible_command (_("select all before cursor"));
1492 end = cursor->current_frame - 1;
1501 if (selection->tracks.empty()) {
1504 ts = &selection->tracks;
1507 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1508 if ((*iter)->hidden()) {
1511 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1513 selection->set (touched);
1514 commit_reversible_command ();
1518 Editor::select_all_selectables_using_edit (bool after)
1522 list<Selectable *> touched;
1525 begin_reversible_command (_("select all after edit"));
1526 start = get_preferred_edit_position();
1527 end = _session->current_end_frame();
1529 if ((end = get_preferred_edit_position()) > 1) {
1530 begin_reversible_command (_("select all before edit"));
1541 if (selection->tracks.empty()) {
1544 ts = &selection->tracks;
1547 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1548 if ((*iter)->hidden()) {
1551 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1553 selection->set (touched);
1554 commit_reversible_command ();
1558 Editor::select_all_selectables_between (bool /*within*/)
1562 list<Selectable *> touched;
1564 if (!get_edit_op_range (start, end)) {
1570 if (selection->tracks.empty()) {
1573 ts = &selection->tracks;
1576 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1577 if ((*iter)->hidden()) {
1580 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1583 selection->set (touched);
1587 Editor::select_range_between ()
1592 if (mouse_mode == MouseRange && !selection->time.empty()) {
1593 selection->clear_time ();
1596 if (!get_edit_op_range (start, end)) {
1600 set_mouse_mode (MouseRange);
1601 selection->set (start, end);
1605 Editor::get_edit_op_range (framepos_t& start, framepos_t& end) const
1610 /* in range mode, use any existing selection */
1612 if (mouse_mode == MouseRange && !selection->time.empty()) {
1613 /* we know that these are ordered */
1614 start = selection->time.start();
1615 end = selection->time.end_frame();
1619 if (!mouse_frame (m, ignored)) {
1620 /* mouse is not in a canvas, try playhead+selected marker.
1621 this is probably most true when using menus.
1624 if (selection->markers.empty()) {
1628 start = selection->markers.front()->position();
1629 end = _session->audible_frame();
1633 switch (_edit_point) {
1634 case EditAtPlayhead:
1635 if (selection->markers.empty()) {
1636 /* use mouse + playhead */
1638 end = _session->audible_frame();
1640 /* use playhead + selected marker */
1641 start = _session->audible_frame();
1642 end = selection->markers.front()->position();
1647 /* use mouse + selected marker */
1648 if (selection->markers.empty()) {
1650 end = _session->audible_frame();
1652 start = selection->markers.front()->position();
1657 case EditAtSelectedMarker:
1658 /* use mouse + selected marker */
1659 if (selection->markers.empty()) {
1661 MessageDialog win (_("No edit range defined"),
1666 win.set_secondary_text (
1667 _("the edit point is Selected Marker\nbut there is no selected marker."));
1670 win.set_default_response (RESPONSE_CLOSE);
1671 win.set_position (Gtk::WIN_POS_MOUSE);
1676 return false; // NO RANGE
1678 start = selection->markers.front()->position();
1692 /* turn range into one delimited by start...end,
1702 Editor::deselect_all ()
1704 selection->clear ();
1708 Editor::select_range_around_region (RegionView* rv)
1712 selection->set (&rv->get_time_axis_view());
1714 selection->time.clear ();
1715 boost::shared_ptr<Region> r = rv->region ();
1716 return selection->set (r->position(), r->position() + r->length());