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"
32 #include "audio_time_axis.h"
33 #include "audio_region_view.h"
34 #include "audio_streamview.h"
35 #include "automation_line.h"
36 #include "control_point.h"
37 #include "editor_regions.h"
42 using namespace ARDOUR
;
46 using namespace Gtkmm2ext
;
47 using namespace Editing
;
49 struct TrackViewByPositionSorter
51 bool operator() (const TimeAxisView
* a
, const TimeAxisView
*b
) {
52 return a
->y_position() < b
->y_position();
57 Editor::extend_selection_to_track (TimeAxisView
& view
)
59 if (selection
->selected (&view
)) {
60 /* already selected, do nothing */
64 if (selection
->tracks
.empty()) {
66 if (!selection
->selected (&view
)) {
67 selection
->set (&view
);
74 /* something is already selected, so figure out which range of things to add */
76 TrackViewList to_be_added
;
77 TrackViewList sorted
= track_views
;
78 TrackViewByPositionSorter cmp
;
79 bool passed_clicked
= false;
84 if (!selection
->selected (&view
)) {
85 to_be_added
.push_back (&view
);
88 /* figure out if we should go forward or backwards */
90 for (TrackViewList::iterator i
= sorted
.begin(); i
!= sorted
.end(); ++i
) {
93 passed_clicked
= true;
96 if (selection
->selected (*i
)) {
106 passed_clicked
= false;
110 for (TrackViewList::iterator i
= sorted
.begin(); i
!= sorted
.end(); ++i
) {
113 passed_clicked
= true;
117 if (passed_clicked
) {
118 if ((*i
)->hidden()) {
121 if (selection
->selected (*i
)) {
123 } else if (!(*i
)->hidden()) {
124 to_be_added
.push_back (*i
);
131 for (TrackViewList::reverse_iterator r
= sorted
.rbegin(); r
!= sorted
.rend(); ++r
) {
134 passed_clicked
= true;
138 if (passed_clicked
) {
140 if ((*r
)->hidden()) {
144 if (selection
->selected (*r
)) {
146 } else if (!(*r
)->hidden()) {
147 to_be_added
.push_back (*r
);
153 if (!to_be_added
.empty()) {
154 selection
->add (to_be_added
);
162 Editor::select_all_tracks ()
164 TrackViewList visible_views
;
165 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
166 if ((*i
)->marked_for_display()) {
167 visible_views
.push_back (*i
);
170 selection
->set (visible_views
);
173 /** Select clicked_routeview, unless there are no currently selected
174 * tracks, in which case nothing will happen unless `force' is true.
177 Editor::set_selected_track_as_side_effect (bool force
)
179 if (!clicked_routeview
) {
183 if (!selection
->tracks
.empty()) {
184 if (!selection
->selected (clicked_routeview
)) {
185 selection
->add (clicked_routeview
);
189 selection
->set (clicked_routeview
);
194 Editor::set_selected_track (TimeAxisView
& view
, Selection::Operation op
, bool no_remove
)
197 case Selection::Toggle
:
198 if (selection
->selected (&view
)) {
200 selection
->remove (&view
);
203 selection
->add (&view
);
208 if (!selection
->selected (&view
)) {
209 selection
->add (&view
);
214 selection
->set (&view
);
217 case Selection::Extend
:
218 extend_selection_to_track (view
);
224 Editor::set_selected_track_from_click (bool press
, Selection::Operation op
, bool no_remove
)
226 if (!clicked_routeview
) {
234 set_selected_track (*clicked_routeview
, op
, no_remove
);
238 Editor::set_selected_control_point_from_click (Selection::Operation op
, bool /*no_remove*/)
240 if (!clicked_control_point
) {
244 if (clicked_control_point
->selected()) {
245 /* the clicked control point is already selected; others may be as well, so
246 don't change the selection.
251 /* We know the ControlPoint that was clicked, but (as discussed in automation_selectable.h)
252 * selected automation data are described by areas on the AutomationLine. A ControlPoint
253 * represents any model points in the space that it takes up, so the AutomationSelectable
254 * needs to be the size of the ControlPoint.
257 double const size
= clicked_control_point
->size ();
259 nframes64_t
const x1
= pixel_to_frame (clicked_control_point
->get_x() - size
/ 2);
260 nframes64_t
const x2
= pixel_to_frame (clicked_control_point
->get_x() + size
/ 2);
261 double y1
= clicked_control_point
->get_y() - size
/ 2;
262 double y2
= clicked_control_point
->get_y() + size
/ 2;
264 /* convert the y values to trackview space */
266 clicked_control_point
->line().parent_group().i2w (dummy
, y1
);
267 clicked_control_point
->line().parent_group().i2w (dummy
, y2
);
268 _trackview_group
->w2i (dummy
, y1
);
269 _trackview_group
->w2i (dummy
, y2
);
271 /* and set up the selection */
272 return select_all_within (x1
, x2
, y1
, y2
, selection
->tracks
, Selection::Set
);
276 Editor::get_onscreen_tracks (TrackViewList
& tvl
)
278 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
279 if ((*i
)->y_position() < _canvas_height
) {
285 /** Call a slot for a given `basis' track and also for any track that is in the same
286 * active route group with a particular set of properties.
288 * @param sl Slot to call.
289 * @param basis Basis track.
290 * @param prop Properties that active edit groups must share to be included in the map.
294 Editor::mapover_tracks (sigc::slot
<void, RouteTimeAxisView
&, uint32_t> sl
, TimeAxisView
* basis
, PBD::PropertyID prop
) const
296 RouteTimeAxisView
* route_basis
= dynamic_cast<RouteTimeAxisView
*> (basis
);
298 if (route_basis
== 0) {
302 set
<RouteTimeAxisView
*> tracks
;
303 tracks
.insert (route_basis
);
305 RouteGroup
* group
= route_basis
->route()->route_group();
307 if (group
&& group
->enabled_property(prop
) && group
->enabled_property (Properties::active
.property_id
) ) {
309 /* the basis is a member of an active route group, with the appropriate
310 properties; find other members */
312 for (TrackViewList::const_iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
313 RouteTimeAxisView
* v
= dynamic_cast<RouteTimeAxisView
*> (*i
);
314 if (v
&& v
->route()->route_group() == group
) {
321 uint32_t const sz
= tracks
.size ();
323 for (set
<RouteTimeAxisView
*>::iterator i
= tracks
.begin(); i
!= tracks
.end(); ++i
) {
329 Editor::mapped_get_equivalent_regions (RouteTimeAxisView
& tv
, uint32_t, RegionView
* basis
, vector
<RegionView
*>* all_equivs
) const
331 boost::shared_ptr
<Playlist
> pl
;
332 vector
<boost::shared_ptr
<Region
> > results
;
334 boost::shared_ptr
<Track
> tr
;
336 if ((tr
= tv
.track()) == 0) {
341 if (&tv
== &basis
->get_time_axis_view()) {
342 /* looking in same track as the original */
346 if ((pl
= tr
->playlist()) != 0) {
347 pl
->get_equivalent_regions (basis
->region(), results
);
350 for (vector
<boost::shared_ptr
<Region
> >::iterator ir
= results
.begin(); ir
!= results
.end(); ++ir
) {
351 if ((marv
= tv
.view()->find_view (*ir
)) != 0) {
352 all_equivs
->push_back (marv
);
358 Editor::get_equivalent_regions (RegionView
* basis
, vector
<RegionView
*>& equivalent_regions
, PBD::PropertyID property
) const
360 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions
), basis
, &equivalent_regions
), &basis
->get_trackview(), property
);
362 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
364 equivalent_regions
.push_back (basis
);
368 Editor::get_equivalent_regions (RegionSelection
& basis
, PBD::PropertyID prop
) const
370 RegionSelection equivalent
;
372 for (RegionSelection::const_iterator i
= basis
.begin(); i
!= basis
.end(); ++i
) {
374 vector
<RegionView
*> eq
;
377 sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions
), *i
, &eq
),
378 &(*i
)->get_trackview(), prop
381 for (vector
<RegionView
*>::iterator j
= eq
.begin(); j
!= eq
.end(); ++j
) {
393 Editor::get_regionview_count_from_region_list (boost::shared_ptr
<Region
> region
)
395 int region_count
= 0;
397 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
399 RouteTimeAxisView
* tatv
;
401 if ((tatv
= dynamic_cast<RouteTimeAxisView
*> (*i
)) != 0) {
403 boost::shared_ptr
<Playlist
> pl
;
404 vector
<boost::shared_ptr
<Region
> > results
;
406 boost::shared_ptr
<Track
> tr
;
408 if ((tr
= tatv
->track()) == 0) {
413 if ((pl
= (tr
->playlist())) != 0) {
414 pl
->get_region_list_equivalent_regions (region
, results
);
417 for (vector
<boost::shared_ptr
<Region
> >::iterator ir
= results
.begin(); ir
!= results
.end(); ++ir
) {
418 if ((marv
= tatv
->view()->find_view (*ir
)) != 0) {
431 Editor::set_selected_regionview_from_click (bool press
, Selection::Operation op
, bool /*no_track_remove*/)
433 vector
<RegionView
*> all_equivalent_regions
;
436 if (!clicked_regionview
|| !clicked_routeview
) {
441 button_release_can_deselect
= false;
444 if (op
== Selection::Toggle
|| op
== Selection::Set
) {
448 case Selection::Toggle
:
450 if (selection
->selected (clicked_regionview
)) {
453 /* whatever was clicked was selected already; do nothing here but allow
454 the button release to deselect it
457 button_release_can_deselect
= true;
461 if (button_release_can_deselect
) {
463 /* just remove this one region, but only on a permitted button release */
465 selection
->remove (clicked_regionview
);
468 /* no more deselect action on button release till a new press
469 finds an already selected object.
472 button_release_can_deselect
= false;
480 if (selection
->selected (clicked_routeview
)) {
481 get_equivalent_regions (clicked_regionview
, all_equivalent_regions
, ARDOUR::Properties::select
.property_id
);
483 all_equivalent_regions
.push_back (clicked_regionview
);
486 /* add all the equivalent regions, but only on button press */
488 if (!all_equivalent_regions
.empty()) {
492 selection
->add (all_equivalent_regions
);
498 if (!selection
->selected (clicked_regionview
)) {
499 get_equivalent_regions (clicked_regionview
, all_equivalent_regions
, ARDOUR::Properties::select
.property_id
);
500 selection
->set (all_equivalent_regions
);
503 /* no commit necessary: clicked on an already selected region */
513 } else if (op
== Selection::Extend
) {
515 list
<Selectable
*> results
;
516 nframes64_t last_frame
;
517 nframes64_t first_frame
;
518 bool same_track
= false;
520 /* 1. find the last selected regionview in the track that was clicked in */
523 first_frame
= max_frames
;
525 for (RegionSelection::iterator x
= selection
->regions
.begin(); x
!= selection
->regions
.end(); ++x
) {
526 if (&(*x
)->get_time_axis_view() == &clicked_regionview
->get_time_axis_view()) {
528 if ((*x
)->region()->last_frame() > last_frame
) {
529 last_frame
= (*x
)->region()->last_frame();
532 if ((*x
)->region()->first_frame() < first_frame
) {
533 first_frame
= (*x
)->region()->first_frame();
542 /* 2. figure out the boundaries for our search for new objects */
544 switch (clicked_regionview
->region()->coverage (first_frame
, last_frame
)) {
546 if (last_frame
< clicked_regionview
->region()->first_frame()) {
547 first_frame
= last_frame
;
548 last_frame
= clicked_regionview
->region()->last_frame();
550 last_frame
= first_frame
;
551 first_frame
= clicked_regionview
->region()->first_frame();
555 case OverlapExternal
:
556 if (last_frame
< clicked_regionview
->region()->first_frame()) {
557 first_frame
= last_frame
;
558 last_frame
= clicked_regionview
->region()->last_frame();
560 last_frame
= first_frame
;
561 first_frame
= clicked_regionview
->region()->first_frame();
565 case OverlapInternal
:
566 if (last_frame
< clicked_regionview
->region()->first_frame()) {
567 first_frame
= last_frame
;
568 last_frame
= clicked_regionview
->region()->last_frame();
570 last_frame
= first_frame
;
571 first_frame
= clicked_regionview
->region()->first_frame();
577 /* nothing to do except add clicked region to selection, since it
578 overlaps with the existing selection in this track.
585 /* click in a track that has no regions selected, so extend vertically
586 to pick out all regions that are defined by the existing selection
591 first_frame
= entered_regionview
->region()->position();
592 last_frame
= entered_regionview
->region()->last_frame();
594 for (RegionSelection::iterator i
= selection
->regions
.begin(); i
!= selection
->regions
.end(); ++i
) {
595 if ((*i
)->region()->position() < first_frame
) {
596 first_frame
= (*i
)->region()->position();
598 if ((*i
)->region()->last_frame() + 1 > last_frame
) {
599 last_frame
= (*i
)->region()->last_frame();
604 /* 2. find all the tracks we should select in */
606 set
<RouteTimeAxisView
*> relevant_tracks
;
608 for (TrackSelection::iterator i
= selection
->tracks
.begin(); i
!= selection
->tracks
.end(); ++i
) {
609 RouteTimeAxisView
* r
= dynamic_cast<RouteTimeAxisView
*> (*i
);
611 relevant_tracks
.insert (r
);
615 set
<RouteTimeAxisView
*> already_in_selection
;
617 if (relevant_tracks
.empty()) {
619 /* no tracks selected .. thus .. if the
620 regionview we're in isn't selected
621 (i.e. we're about to extend to it), then
622 find all tracks between the this one and
626 if (!selection
->selected (entered_regionview
)) {
628 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*> (&entered_regionview
->get_time_axis_view());
632 /* add this track to the ones we will search */
634 relevant_tracks
.insert (rtv
);
636 /* find the track closest to this one that
637 already a selected region.
640 RouteTimeAxisView
* closest
= 0;
641 int distance
= INT_MAX
;
642 int key
= rtv
->route()->order_key ("editor");
644 for (RegionSelection::iterator x
= selection
->regions
.begin(); x
!= selection
->regions
.end(); ++x
) {
646 RouteTimeAxisView
* artv
= dynamic_cast<RouteTimeAxisView
*>(&(*x
)->get_time_axis_view());
648 if (artv
&& artv
!= rtv
) {
650 pair
<set
<RouteTimeAxisView
*>::iterator
,bool> result
;
652 result
= already_in_selection
.insert (artv
);
655 /* newly added to already_in_selection */
657 int d
= artv
->route()->order_key ("editor");
661 if (abs (d
) < distance
) {
671 /* now add all tracks between that one and this one */
673 int okey
= closest
->route()->order_key ("editor");
679 for (TrackViewList::iterator x
= track_views
.begin(); x
!= track_views
.end(); ++x
) {
680 RouteTimeAxisView
* artv
= dynamic_cast<RouteTimeAxisView
*>(*x
);
681 if (artv
&& artv
!= rtv
) {
683 int k
= artv
->route()->order_key ("editor");
685 if (k
>= okey
&& k
<= key
) {
687 /* in range but don't add it if
688 it already has tracks selected.
689 this avoids odd selection
690 behaviour that feels wrong.
693 if (find (already_in_selection
.begin(),
694 already_in_selection
.end(),
695 artv
) == already_in_selection
.end()) {
697 relevant_tracks
.insert (artv
);
707 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
708 one that was clicked.
711 for (set
<RouteTimeAxisView
*>::iterator t
= relevant_tracks
.begin(); t
!= relevant_tracks
.end(); ++t
) {
712 (*t
)->get_selectables (first_frame
, last_frame
, -1.0, -1.0, results
);
715 /* 4. convert to a vector of regions */
717 vector
<RegionView
*> regions
;
719 for (list
<Selectable
*>::iterator x
= results
.begin(); x
!= results
.end(); ++x
) {
722 if ((arv
= dynamic_cast<RegionView
*>(*x
)) != 0) {
723 regions
.push_back (arv
);
727 if (!regions
.empty()) {
728 selection
->add (regions
);
739 Editor::set_selected_regionview_from_region_list (boost::shared_ptr
<Region
> region
, Selection::Operation op
)
741 vector
<RegionView
*> all_equivalent_regions
;
743 get_regions_corresponding_to (region
, all_equivalent_regions
);
745 if (all_equivalent_regions
.empty()) {
749 begin_reversible_command (_("set selected regions"));
752 case Selection::Toggle
:
753 /* XXX this is not correct */
754 selection
->toggle (all_equivalent_regions
);
757 selection
->set (all_equivalent_regions
);
759 case Selection::Extend
:
760 selection
->add (all_equivalent_regions
);
763 selection
->add (all_equivalent_regions
);
767 commit_reversible_command () ;
771 Editor::set_selected_regionview_from_map_event (GdkEventAny
* /*ev*/, StreamView
* sv
, boost::weak_ptr
<Region
> weak_r
)
774 boost::shared_ptr
<Region
> r (weak_r
.lock());
780 if ((rv
= sv
->find_view (r
)) == 0) {
784 /* don't reset the selection if its something other than
785 a single other region.
788 if (selection
->regions
.size() > 1) {
792 begin_reversible_command (_("set selected regions"));
796 commit_reversible_command () ;
802 Editor::track_selection_changed ()
804 switch (selection
->tracks
.size()){
808 set_selected_mixer_strip (*(selection
->tracks
.front()));
812 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
813 if (find (selection
->tracks
.begin(), selection
->tracks
.end(), *i
) != selection
->tracks
.end()) {
814 (*i
)->set_selected (true);
816 (*i
)->set_selected (false);
820 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions
, !selection
->tracks
.empty());
824 Editor::time_selection_changed ()
826 if (Profile
->get_sae()) {
830 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
831 (*i
)->hide_selection ();
834 for (TrackSelection::iterator i
= selection
->tracks
.begin(); i
!= selection
->tracks
.end(); ++i
) {
835 (*i
)->show_selection (selection
->time
);
838 if (selection
->time
.empty()) {
839 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions
, false);
841 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions
, true);
846 Editor::sensitize_the_right_region_actions (bool have_selected_regions
)
848 for (vector
<Glib::RefPtr
<Action
> >::iterator x
= ActionManager::region_selection_sensitive_actions
.begin();
849 x
!= ActionManager::region_selection_sensitive_actions
.end(); ++x
) {
851 string accel_path
= (*x
)->get_accel_path ();
854 /* if there is an accelerator, it should always be sensitive
855 to allow for keyboard ops on entered regions.
858 bool known
= ActionManager::lookup_entry (accel_path
, key
);
860 if (known
&& ((key
.get_key() != GDK_VoidSymbol
) && (key
.get_key() != 0))) {
861 (*x
)->set_sensitive (true);
863 (*x
)->set_sensitive (have_selected_regions
);
870 Editor::region_selection_changed ()
872 _regions
->block_change_connection (true);
873 editor_regions_selection_changed_connection
.block(true);
875 _regions
->unselect_all ();
877 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
878 (*i
)->set_selected_regionviews (selection
->regions
);
881 _regions
->set_selected (selection
->regions
);
883 sensitize_the_right_region_actions (!selection
->regions
.empty());
885 _regions
->block_change_connection (false);
886 editor_regions_selection_changed_connection
.block(false);
890 Editor::point_selection_changed ()
892 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
893 (*i
)->set_selected_points (selection
->points
);
898 Editor::select_all_in_track (Selection::Operation op
)
900 list
<Selectable
*> touched
;
902 if (!clicked_routeview
) {
906 clicked_routeview
->get_selectables (0, max_frames
, 0, DBL_MAX
, touched
);
909 case Selection::Toggle
:
910 selection
->add (touched
);
913 selection
->set (touched
);
915 case Selection::Extend
:
916 /* meaningless, because we're selecting everything */
919 selection
->add (touched
);
925 Editor::select_all (Selection::Operation op
)
927 list
<Selectable
*> touched
;
929 for (TrackViewList::iterator iter
= track_views
.begin(); iter
!= track_views
.end(); ++iter
) {
930 if ((*iter
)->hidden()) {
933 (*iter
)->get_selectables (0, max_frames
, 0, DBL_MAX
, touched
);
935 begin_reversible_command (_("select all"));
938 selection
->add (touched
);
940 case Selection::Toggle
:
941 selection
->add (touched
);
944 selection
->set (touched
);
946 case Selection::Extend
:
947 /* meaningless, because we're selecting everything */
950 commit_reversible_command ();
953 Editor::invert_selection_in_track ()
955 list
<Selectable
*> touched
;
957 if (!clicked_routeview
) {
961 clicked_routeview
->get_inverted_selectables (*selection
, touched
);
962 selection
->set (touched
);
966 Editor::invert_selection ()
968 list
<Selectable
*> touched
;
970 for (TrackViewList::iterator iter
= track_views
.begin(); iter
!= track_views
.end(); ++iter
) {
971 if ((*iter
)->hidden()) {
974 (*iter
)->get_inverted_selectables (*selection
, touched
);
977 selection
->set (touched
);
980 /** @param top Top (lower) y limit in trackview coordinates.
981 * @param bottom Bottom (higher) y limit in trackview coordinates.
984 Editor::select_all_within (nframes64_t start
, nframes64_t end
, double top
, double bot
, const TrackViewList
& tracklist
, Selection::Operation op
)
986 list
<Selectable
*> found
;
988 for (TrackViewList::const_iterator iter
= tracklist
.begin(); iter
!= tracklist
.end(); ++iter
) {
990 if ((*iter
)->hidden()) {
994 (*iter
)->get_selectables (start
, end
, top
, bot
, found
);
1001 begin_reversible_command (_("select all within"));
1003 case Selection::Add
:
1004 selection
->add (found
);
1006 case Selection::Toggle
:
1007 selection
->toggle (found
);
1009 case Selection::Set
:
1010 selection
->set (found
);
1012 case Selection::Extend
:
1013 /* not defined yet */
1017 commit_reversible_command ();
1019 return !found
.empty();
1023 Editor::set_selection_from_region ()
1025 if (selection
->regions
.empty()) {
1029 selection
->set (selection
->regions
.start(), selection
->regions
.end_frame());
1030 if (!Profile
->get_sae()) {
1031 set_mouse_mode (Editing::MouseRange
, false);
1036 Editor::set_selection_from_punch()
1040 if ((location
= _session
->locations()->auto_punch_location()) == 0) {
1044 set_selection_from_range (*location
);
1048 Editor::set_selection_from_loop()
1052 if ((location
= _session
->locations()->auto_loop_location()) == 0) {
1055 set_selection_from_range (*location
);
1059 Editor::set_selection_from_range (Location
& loc
)
1061 begin_reversible_command (_("set selection from range"));
1062 selection
->set (loc
.start(), loc
.end());
1063 commit_reversible_command ();
1065 if (!Profile
->get_sae()) {
1066 set_mouse_mode (Editing::MouseRange
, false);
1071 Editor::select_all_selectables_using_time_selection ()
1073 list
<Selectable
*> touched
;
1075 if (selection
->time
.empty()) {
1079 nframes64_t start
= selection
->time
[clicked_selection
].start
;
1080 nframes64_t end
= selection
->time
[clicked_selection
].end
;
1082 if (end
- start
< 1) {
1088 if (selection
->tracks
.empty()) {
1091 ts
= &selection
->tracks
;
1094 for (TrackViewList::iterator iter
= ts
->begin(); iter
!= ts
->end(); ++iter
) {
1095 if ((*iter
)->hidden()) {
1098 (*iter
)->get_selectables (start
, end
- 1, 0, DBL_MAX
, touched
);
1101 begin_reversible_command (_("select all from range"));
1102 selection
->set (touched
);
1103 commit_reversible_command ();
1108 Editor::select_all_selectables_using_punch()
1110 Location
* location
= _session
->locations()->auto_punch_location();
1111 list
<Selectable
*> touched
;
1113 if (location
== 0 || (location
->end() - location
->start() <= 1)) {
1120 if (selection
->tracks
.empty()) {
1123 ts
= &selection
->tracks
;
1126 for (TrackViewList::iterator iter
= ts
->begin(); iter
!= ts
->end(); ++iter
) {
1127 if ((*iter
)->hidden()) {
1130 (*iter
)->get_selectables (location
->start(), location
->end() - 1, 0, DBL_MAX
, touched
);
1132 begin_reversible_command (_("select all from punch"));
1133 selection
->set (touched
);
1134 commit_reversible_command ();
1139 Editor::select_all_selectables_using_loop()
1141 Location
* location
= _session
->locations()->auto_loop_location();
1142 list
<Selectable
*> touched
;
1144 if (location
== 0 || (location
->end() - location
->start() <= 1)) {
1151 if (selection
->tracks
.empty()) {
1154 ts
= &selection
->tracks
;
1157 for (TrackViewList::iterator iter
= ts
->begin(); iter
!= ts
->end(); ++iter
) {
1158 if ((*iter
)->hidden()) {
1161 (*iter
)->get_selectables (location
->start(), location
->end() - 1, 0, DBL_MAX
, touched
);
1163 begin_reversible_command (_("select all from loop"));
1164 selection
->set (touched
);
1165 commit_reversible_command ();
1170 Editor::select_all_selectables_using_cursor (EditorCursor
*cursor
, bool after
)
1174 list
<Selectable
*> touched
;
1177 begin_reversible_command (_("select all after cursor"));
1178 start
= cursor
->current_frame
;
1179 end
= _session
->current_end_frame();
1181 if (cursor
->current_frame
> 0) {
1182 begin_reversible_command (_("select all before cursor"));
1184 end
= cursor
->current_frame
- 1;
1193 if (selection
->tracks
.empty()) {
1196 ts
= &selection
->tracks
;
1199 for (TrackViewList::iterator iter
= ts
->begin(); iter
!= ts
->end(); ++iter
) {
1200 if ((*iter
)->hidden()) {
1203 (*iter
)->get_selectables (start
, end
, 0, DBL_MAX
, touched
);
1205 selection
->set (touched
);
1206 commit_reversible_command ();
1210 Editor::select_all_selectables_using_edit (bool after
)
1214 list
<Selectable
*> touched
;
1217 begin_reversible_command (_("select all after edit"));
1218 start
= get_preferred_edit_position();
1219 end
= _session
->current_end_frame();
1221 if ((end
= get_preferred_edit_position()) > 1) {
1222 begin_reversible_command (_("select all before edit"));
1233 if (selection
->tracks
.empty()) {
1236 ts
= &selection
->tracks
;
1239 for (TrackViewList::iterator iter
= ts
->begin(); iter
!= ts
->end(); ++iter
) {
1240 if ((*iter
)->hidden()) {
1243 (*iter
)->get_selectables (start
, end
, 0, DBL_MAX
, touched
);
1245 selection
->set (touched
);
1246 commit_reversible_command ();
1250 Editor::select_all_selectables_between (bool /*within*/)
1254 list
<Selectable
*> touched
;
1256 if (!get_edit_op_range (start
, end
)) {
1262 if (selection
->tracks
.empty()) {
1265 ts
= &selection
->tracks
;
1268 for (TrackViewList::iterator iter
= ts
->begin(); iter
!= ts
->end(); ++iter
) {
1269 if ((*iter
)->hidden()) {
1272 (*iter
)->get_selectables (start
, end
, 0, DBL_MAX
, touched
);
1275 selection
->set (touched
);
1279 Editor::select_range_between ()
1284 if (!get_edit_op_range (start
, end
)) {
1288 set_mouse_mode (MouseRange
);
1289 selection
->set (start
, end
);
1293 Editor::get_edit_op_range (nframes64_t
& start
, nframes64_t
& end
) const
1298 /* in range mode, use any existing selection */
1300 if (mouse_mode
== MouseRange
&& !selection
->time
.empty()) {
1301 /* we know that these are ordered */
1302 start
= selection
->time
.start();
1303 end
= selection
->time
.end_frame();
1307 if (!mouse_frame (m
, ignored
)) {
1308 /* mouse is not in a canvas, try playhead+selected marker.
1309 this is probably most true when using menus.
1312 if (selection
->markers
.empty()) {
1316 start
= selection
->markers
.front()->position();
1317 end
= _session
->audible_frame();
1321 switch (_edit_point
) {
1322 case EditAtPlayhead
:
1323 if (selection
->markers
.empty()) {
1324 /* use mouse + playhead */
1326 end
= _session
->audible_frame();
1328 /* use playhead + selected marker */
1329 start
= _session
->audible_frame();
1330 end
= selection
->markers
.front()->position();
1335 /* use mouse + selected marker */
1336 if (selection
->markers
.empty()) {
1338 end
= _session
->audible_frame();
1340 start
= selection
->markers
.front()->position();
1345 case EditAtSelectedMarker
:
1346 /* use mouse + selected marker */
1347 if (selection
->markers
.empty()) {
1349 MessageDialog
win (_("No edit range defined"),
1354 win
.set_secondary_text (
1355 _("the edit point is Selected Marker\nbut there is no selected marker."));
1358 win
.set_default_response (RESPONSE_CLOSE
);
1359 win
.set_position (Gtk::WIN_POS_MOUSE
);
1364 return false; // NO RANGE
1366 start
= selection
->markers
.front()->position();
1380 /* turn range into one delimited by start...end,
1390 Editor::deselect_all ()
1392 selection
->clear ();
1396 Editor::select_range_around_region (RegionView
* rv
)
1400 selection
->set (&rv
->get_time_axis_view());
1402 selection
->time
.clear ();
1403 boost::shared_ptr
<Region
> r
= rv
->region ();
1404 return selection
->set (r
->position(), r
->position() + r
->length());