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_multichannel_audio = false;
977 bool have_midi = false;
978 bool have_locked = false;
979 bool have_unlocked = false;
980 bool have_position_lock_style_audio = false;
981 bool have_position_lock_style_music = false;
982 bool have_muted = false;
983 bool have_unmuted = false;
984 bool have_opaque = false;
985 bool have_non_opaque = false;
986 bool have_not_at_natural_position = false;
987 bool have_envelope_visible = false;
988 bool have_envelope_invisible = false;
989 bool have_envelope_active = false;
990 bool have_envelope_inactive = false;
991 bool have_non_unity_scale_amplitude = false;
992 bool have_compound_regions = false;
994 for (list<RegionView*>::const_iterator i = rs.begin(); i != rs.end(); ++i) {
996 boost::shared_ptr<Region> r = (*i)->region ();
997 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
1001 if (ar->n_channels() > 1) {
1002 have_multichannel_audio = true;
1006 if (boost::dynamic_pointer_cast<MidiRegion> (r)) {
1010 if (r->is_compound()) {
1011 have_compound_regions = true;
1017 have_unlocked = true;
1020 if (r->position_lock_style() == MusicTime) {
1021 have_position_lock_style_music = true;
1023 have_position_lock_style_audio = true;
1029 have_unmuted = true;
1035 have_non_opaque = true;
1038 if (!r->at_natural_position()) {
1039 have_not_at_natural_position = true;
1043 /* its a bit unfortunate that "envelope visible" is a view-only
1044 property. we have to find the regionview to able to check
1045 its current setting.
1048 have_envelope_invisible = false;
1051 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
1053 if (arv->envelope_visible()) {
1054 have_envelope_visible = true;
1056 have_envelope_invisible = true;
1061 if (ar->envelope_active()) {
1062 have_envelope_active = true;
1064 have_envelope_inactive = true;
1067 if (ar->scale_amplitude() != 1) {
1068 have_non_unity_scale_amplitude = true;
1073 if (rs.size() > 1) {
1074 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1075 _region_actions->get_action("show-region-properties")->set_sensitive (false);
1076 _region_actions->get_action("rename-region")->set_sensitive (false);
1078 _region_actions->get_action("combine-regions")->set_sensitive (true);
1080 _region_actions->get_action("combine-regions")->set_sensitive (false);
1082 } else if (rs.size() == 1) {
1083 _region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
1084 _region_actions->get_action("close-region-gaps")->set_sensitive (false);
1085 _region_actions->get_action("combine-regions")->set_sensitive (false);
1088 if (!have_multichannel_audio) {
1089 _region_actions->get_action("split-multichannel-region")->set_sensitive (false);
1093 _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1094 _region_actions->get_action("quantize-region")->set_sensitive (false);
1095 _region_actions->get_action("fork-region")->set_sensitive (false);
1096 _region_actions->get_action("transpose-region")->set_sensitive (false);
1099 if (_edit_point == EditAtMouse) {
1100 _region_actions->get_action("set-region-sync-position")->set_sensitive (false);
1101 _region_actions->get_action("trim-front")->set_sensitive (false);
1102 _region_actions->get_action("trim-back")->set_sensitive (false);
1103 _region_actions->get_action("split-region")->set_sensitive (false);
1104 _region_actions->get_action("place-transient")->set_sensitive (false);
1107 if (have_compound_regions) {
1108 _region_actions->get_action("uncombine-regions")->set_sensitive (true);
1110 _region_actions->get_action("uncombine-regions")->set_sensitive (false);
1115 if (have_envelope_visible && !have_envelope_invisible) {
1116 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-visible"))->set_active ();
1117 } else if (have_envelope_visible && have_envelope_invisible) {
1118 // _region_actions->get_action("toggle-region-gain-envelope-visible")->set_inconsistent ();
1121 if (have_envelope_active && !have_envelope_inactive) {
1122 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active ();
1123 } else if (have_envelope_active && have_envelope_inactive) {
1124 // _region_actions->get_action("toggle-region-gain-envelope-active")->set_inconsistent ();
1129 _region_actions->get_action("analyze-region")->set_sensitive (false);
1130 _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
1131 _region_actions->get_action("toggle-region-gain-envelope-visible")->set_sensitive (false);
1132 _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
1133 _region_actions->get_action("pitch-shift-region")->set_sensitive (false);
1137 if (!have_non_unity_scale_amplitude || !have_audio) {
1138 _region_actions->get_action("reset-region-scale-amplitude")->set_sensitive (false);
1141 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"))->set_active (have_locked && !have_unlocked);
1142 if (have_locked && have_unlocked) {
1143 // _region_actions->get_action("toggle-region-lock")->set_inconsistent ();
1146 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);
1148 if (have_position_lock_style_music && have_position_lock_style_audio) {
1149 // _region_actions->get_action("toggle-region-lock-style")->set_inconsistent ();
1152 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"))->set_active (have_muted && !have_unmuted);
1153 if (have_muted && have_unmuted) {
1154 // _region_actions->get_action("toggle-region-mute")->set_inconsistent ();
1157 Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"))->set_active (have_opaque && !have_non_opaque);
1158 if (have_opaque && have_non_opaque) {
1159 // _region_actions->get_action("toggle-opaque-region")->set_inconsistent ();
1162 if (!have_not_at_natural_position) {
1163 _region_actions->get_action("naturalize-region")->set_sensitive (false);
1166 /* XXX: should also check that there is a track of the appropriate type for the selected region */
1167 if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
1168 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (false);
1170 _region_actions->get_action("insert-region-from-region-list")->set_sensitive (true);
1173 _ignore_region_action = false;
1175 _all_region_actions_sensitized = false;
1180 Editor::region_selection_changed ()
1182 _regions->block_change_connection (true);
1183 editor_regions_selection_changed_connection.block(true);
1185 if (_region_selection_change_updates_region_list) {
1186 _regions->unselect_all ();
1189 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1190 (*i)->set_selected_regionviews (selection->regions);
1193 if (_region_selection_change_updates_region_list) {
1194 _regions->set_selected (selection->regions);
1197 _regions->block_change_connection (false);
1198 editor_regions_selection_changed_connection.block(false);
1200 if (!_all_region_actions_sensitized) {
1201 /* This selection change might have changed what region actions
1202 are allowed, so sensitize them all in case a key is pressed.
1204 sensitize_all_region_actions (true);
1209 Editor::point_selection_changed ()
1211 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1212 (*i)->set_selected_points (selection->points);
1217 Editor::select_all_in_track (Selection::Operation op)
1219 list<Selectable *> touched;
1221 if (!clicked_routeview) {
1225 clicked_routeview->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1228 case Selection::Toggle:
1229 selection->add (touched);
1231 case Selection::Set:
1232 selection->set (touched);
1234 case Selection::Extend:
1235 /* meaningless, because we're selecting everything */
1237 case Selection::Add:
1238 selection->add (touched);
1244 Editor::select_all_internal_edit (Selection::Operation)
1246 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1247 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1249 mrv->select_all_notes ();
1255 Editor::select_all (Selection::Operation op)
1257 list<Selectable *> touched;
1259 if (_internal_editing) {
1260 select_all_internal_edit (op);
1264 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1265 if ((*iter)->hidden()) {
1268 (*iter)->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1270 begin_reversible_command (_("select all"));
1272 case Selection::Add:
1273 selection->add (touched);
1275 case Selection::Toggle:
1276 selection->add (touched);
1278 case Selection::Set:
1279 selection->set (touched);
1281 case Selection::Extend:
1282 /* meaningless, because we're selecting everything */
1285 commit_reversible_command ();
1289 Editor::invert_selection_in_track ()
1291 list<Selectable *> touched;
1293 if (!clicked_routeview) {
1297 clicked_routeview->get_inverted_selectables (*selection, touched);
1298 selection->set (touched);
1302 Editor::invert_selection ()
1304 list<Selectable *> touched;
1306 if (_internal_editing) {
1307 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1308 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1310 mrv->invert_selection ();
1316 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1317 if ((*iter)->hidden()) {
1320 (*iter)->get_inverted_selectables (*selection, touched);
1323 selection->set (touched);
1326 /** @param start Start time in session frames.
1327 * @param end End time in session frames.
1328 * @param top Top (lower) y limit in trackview coordinates (ie 0 at the top of the track view)
1329 * @param bottom Bottom (higher) y limit in trackview coordinates (ie 0 at the top of the track view)
1330 * @param preserve_if_selected true to leave the current selection alone if we're adding to the selection and all of the selectables
1331 * within the region are already selected.
1334 Editor::select_all_within (framepos_t start, framepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected)
1336 list<Selectable*> found;
1338 for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1340 if ((*iter)->hidden()) {
1344 (*iter)->get_selectables (start, end, top, bot, found);
1347 if (found.empty()) {
1351 if (preserve_if_selected && op != Selection::Toggle) {
1352 list<Selectable*>::iterator i = found.begin();
1353 while (i != found.end() && (*i)->get_selected()) {
1357 if (i == found.end()) {
1362 begin_reversible_command (_("select all within"));
1364 case Selection::Add:
1365 selection->add (found);
1367 case Selection::Toggle:
1368 selection->toggle (found);
1370 case Selection::Set:
1371 selection->set (found);
1373 case Selection::Extend:
1374 /* not defined yet */
1378 commit_reversible_command ();
1382 Editor::set_selection_from_region ()
1384 if (selection->regions.empty()) {
1388 selection->set (selection->regions.start(), selection->regions.end_frame());
1389 if (!Profile->get_sae()) {
1390 set_mouse_mode (Editing::MouseRange, false);
1395 Editor::set_selection_from_punch()
1399 if ((location = _session->locations()->auto_punch_location()) == 0) {
1403 set_selection_from_range (*location);
1407 Editor::set_selection_from_loop()
1411 if ((location = _session->locations()->auto_loop_location()) == 0) {
1414 set_selection_from_range (*location);
1418 Editor::set_selection_from_range (Location& loc)
1420 begin_reversible_command (_("set selection from range"));
1421 selection->set (loc.start(), loc.end());
1422 commit_reversible_command ();
1424 if (!Profile->get_sae()) {
1425 set_mouse_mode (Editing::MouseRange, false);
1430 Editor::select_all_selectables_using_time_selection ()
1432 list<Selectable *> touched;
1434 if (selection->time.empty()) {
1438 framepos_t start = selection->time[clicked_selection].start;
1439 framepos_t end = selection->time[clicked_selection].end;
1441 if (end - start < 1) {
1447 if (selection->tracks.empty()) {
1450 ts = &selection->tracks;
1453 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1454 if ((*iter)->hidden()) {
1457 (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1460 begin_reversible_command (_("select all from range"));
1461 selection->set (touched);
1462 commit_reversible_command ();
1467 Editor::select_all_selectables_using_punch()
1469 Location* location = _session->locations()->auto_punch_location();
1470 list<Selectable *> touched;
1472 if (location == 0 || (location->end() - location->start() <= 1)) {
1479 if (selection->tracks.empty()) {
1482 ts = &selection->tracks;
1485 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1486 if ((*iter)->hidden()) {
1489 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1491 begin_reversible_command (_("select all from punch"));
1492 selection->set (touched);
1493 commit_reversible_command ();
1498 Editor::select_all_selectables_using_loop()
1500 Location* location = _session->locations()->auto_loop_location();
1501 list<Selectable *> touched;
1503 if (location == 0 || (location->end() - location->start() <= 1)) {
1510 if (selection->tracks.empty()) {
1513 ts = &selection->tracks;
1516 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1517 if ((*iter)->hidden()) {
1520 (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1522 begin_reversible_command (_("select all from loop"));
1523 selection->set (touched);
1524 commit_reversible_command ();
1529 Editor::select_all_selectables_using_cursor (EditorCursor *cursor, bool after)
1533 list<Selectable *> touched;
1536 start = cursor->current_frame;
1537 end = _session->current_end_frame();
1539 if (cursor->current_frame > 0) {
1541 end = cursor->current_frame - 1;
1547 if (_internal_editing) {
1548 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1549 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1551 mrv->select_range (start, end);
1558 begin_reversible_command (_("select all after cursor"));
1560 begin_reversible_command (_("select all before cursor"));
1565 if (selection->tracks.empty()) {
1568 ts = &selection->tracks;
1571 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1572 if ((*iter)->hidden()) {
1575 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1577 selection->set (touched);
1578 commit_reversible_command ();
1582 Editor::select_all_selectables_using_edit (bool after)
1586 list<Selectable *> touched;
1589 start = get_preferred_edit_position();
1590 end = _session->current_end_frame();
1592 if ((end = get_preferred_edit_position()) > 1) {
1600 if (_internal_editing) {
1601 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1602 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1603 mrv->select_range (start, end);
1609 begin_reversible_command (_("select all after edit"));
1611 begin_reversible_command (_("select all before edit"));
1616 if (selection->tracks.empty()) {
1619 ts = &selection->tracks;
1622 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1623 if ((*iter)->hidden()) {
1626 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1628 selection->set (touched);
1629 commit_reversible_command ();
1633 Editor::select_all_selectables_between (bool /*within*/)
1637 list<Selectable *> touched;
1639 if (!get_edit_op_range (start, end)) {
1643 if (_internal_editing) {
1644 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1645 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1646 mrv->select_range (start, end);
1653 if (selection->tracks.empty()) {
1656 ts = &selection->tracks;
1659 for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1660 if ((*iter)->hidden()) {
1663 (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1666 selection->set (touched);
1670 Editor::select_range_between ()
1675 if (mouse_mode == MouseRange && !selection->time.empty()) {
1676 selection->clear_time ();
1679 if (!get_edit_op_range (start, end)) {
1683 set_mouse_mode (MouseRange);
1684 selection->set (start, end);
1688 Editor::get_edit_op_range (framepos_t& start, framepos_t& end) const
1693 /* in range mode, use any existing selection */
1695 if (mouse_mode == MouseRange && !selection->time.empty()) {
1696 /* we know that these are ordered */
1697 start = selection->time.start();
1698 end = selection->time.end_frame();
1702 if (!mouse_frame (m, ignored)) {
1703 /* mouse is not in a canvas, try playhead+selected marker.
1704 this is probably most true when using menus.
1707 if (selection->markers.empty()) {
1711 start = selection->markers.front()->position();
1712 end = _session->audible_frame();
1716 switch (_edit_point) {
1717 case EditAtPlayhead:
1718 if (selection->markers.empty()) {
1719 /* use mouse + playhead */
1721 end = _session->audible_frame();
1723 /* use playhead + selected marker */
1724 start = _session->audible_frame();
1725 end = selection->markers.front()->position();
1730 /* use mouse + selected marker */
1731 if (selection->markers.empty()) {
1733 end = _session->audible_frame();
1735 start = selection->markers.front()->position();
1740 case EditAtSelectedMarker:
1741 /* use mouse + selected marker */
1742 if (selection->markers.empty()) {
1744 MessageDialog win (_("No edit range defined"),
1749 win.set_secondary_text (
1750 _("the edit point is Selected Marker\nbut there is no selected marker."));
1753 win.set_default_response (RESPONSE_CLOSE);
1754 win.set_position (Gtk::WIN_POS_MOUSE);
1759 return false; // NO RANGE
1761 start = selection->markers.front()->position();
1775 /* turn range into one delimited by start...end,
1785 Editor::deselect_all ()
1787 selection->clear ();
1791 Editor::select_range_around_region (RegionView* rv)
1795 selection->set (&rv->get_time_axis_view());
1797 selection->time.clear ();
1798 boost::shared_ptr<Region> r = rv->region ();
1799 return selection->set (r->position(), r->position() + r->length());