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
);
297 if (route_basis
== 0) {
301 set
<RouteTimeAxisView
*> tracks
;
302 tracks
.insert (route_basis
);
304 RouteGroup
* group
= route_basis
->route()->route_group();
305 if (group
&& group
->enabled_property (prop
)) {
307 /* the basis is a member of an active route group, with the appropriate
308 properties; find other members */
310 for (TrackViewList::const_iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
311 RouteTimeAxisView
* v
= dynamic_cast<RouteTimeAxisView
*> (*i
);
312 if (v
&& v
->route()->route_group() == group
) {
319 uint32_t const sz
= tracks
.size ();
320 for (set
<RouteTimeAxisView
*>::iterator i
= tracks
.begin(); i
!= tracks
.end(); ++i
) {
326 Editor::mapped_get_equivalent_regions (RouteTimeAxisView
& tv
, uint32_t, RegionView
* basis
, vector
<RegionView
*>* all_equivs
) const
328 boost::shared_ptr
<Playlist
> pl
;
329 vector
<boost::shared_ptr
<Region
> > results
;
331 boost::shared_ptr
<Track
> tr
;
333 if ((tr
= tv
.track()) == 0) {
338 if (&tv
== &basis
->get_time_axis_view()) {
339 /* looking in same track as the original */
343 if ((pl
= tr
->playlist()) != 0) {
344 pl
->get_equivalent_regions (basis
->region(), results
);
347 for (vector
<boost::shared_ptr
<Region
> >::iterator ir
= results
.begin(); ir
!= results
.end(); ++ir
) {
348 if ((marv
= tv
.view()->find_view (*ir
)) != 0) {
349 all_equivs
->push_back (marv
);
355 Editor::get_equivalent_regions (RegionView
* basis
, vector
<RegionView
*>& equivalent_regions
, PBD::PropertyID property
) const
357 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions
), basis
, &equivalent_regions
), &basis
->get_trackview(), property
);
359 /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
361 equivalent_regions
.push_back (basis
);
365 Editor::get_equivalent_regions (RegionSelection
& basis
, PBD::PropertyID prop
) const
367 RegionSelection equivalent
;
369 for (RegionSelection::const_iterator i
= basis
.begin(); i
!= basis
.end(); ++i
) {
371 vector
<RegionView
*> eq
;
374 sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions
), *i
, &eq
),
375 &(*i
)->get_trackview(), prop
378 for (vector
<RegionView
*>::iterator j
= eq
.begin(); j
!= eq
.end(); ++j
) {
390 Editor::get_regionview_count_from_region_list (boost::shared_ptr
<Region
> region
)
392 int region_count
= 0;
394 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
396 RouteTimeAxisView
* tatv
;
398 if ((tatv
= dynamic_cast<RouteTimeAxisView
*> (*i
)) != 0) {
400 boost::shared_ptr
<Playlist
> pl
;
401 vector
<boost::shared_ptr
<Region
> > results
;
403 boost::shared_ptr
<Track
> tr
;
405 if ((tr
= tatv
->track()) == 0) {
410 if ((pl
= (tr
->playlist())) != 0) {
411 pl
->get_region_list_equivalent_regions (region
, results
);
414 for (vector
<boost::shared_ptr
<Region
> >::iterator ir
= results
.begin(); ir
!= results
.end(); ++ir
) {
415 if ((marv
= tatv
->view()->find_view (*ir
)) != 0) {
428 Editor::set_selected_regionview_from_click (bool press
, Selection::Operation op
, bool /*no_track_remove*/)
430 vector
<RegionView
*> all_equivalent_regions
;
433 if (!clicked_regionview
|| !clicked_routeview
) {
438 button_release_can_deselect
= false;
441 if (op
== Selection::Toggle
|| op
== Selection::Set
) {
445 case Selection::Toggle
:
447 if (selection
->selected (clicked_regionview
)) {
450 /* whatever was clicked was selected already; do nothing here but allow
451 the button release to deselect it
454 button_release_can_deselect
= true;
458 if (button_release_can_deselect
) {
460 /* just remove this one region, but only on a permitted button release */
462 selection
->remove (clicked_regionview
);
465 /* no more deselect action on button release till a new press
466 finds an already selected object.
469 button_release_can_deselect
= false;
477 if (selection
->selected (clicked_routeview
)) {
478 get_equivalent_regions (clicked_regionview
, all_equivalent_regions
, ARDOUR::Properties::select
.property_id
);
480 all_equivalent_regions
.push_back (clicked_regionview
);
483 /* add all the equivalent regions, but only on button press */
485 if (!all_equivalent_regions
.empty()) {
489 selection
->add (all_equivalent_regions
);
495 if (!selection
->selected (clicked_regionview
)) {
496 get_equivalent_regions (clicked_regionview
, all_equivalent_regions
, ARDOUR::Properties::select
.property_id
);
497 selection
->set (all_equivalent_regions
);
500 /* no commit necessary: clicked on an already selected region */
510 } else if (op
== Selection::Extend
) {
512 list
<Selectable
*> results
;
513 nframes64_t last_frame
;
514 nframes64_t first_frame
;
515 bool same_track
= false;
517 /* 1. find the last selected regionview in the track that was clicked in */
520 first_frame
= max_frames
;
522 for (RegionSelection::iterator x
= selection
->regions
.begin(); x
!= selection
->regions
.end(); ++x
) {
523 if (&(*x
)->get_time_axis_view() == &clicked_regionview
->get_time_axis_view()) {
525 if ((*x
)->region()->last_frame() > last_frame
) {
526 last_frame
= (*x
)->region()->last_frame();
529 if ((*x
)->region()->first_frame() < first_frame
) {
530 first_frame
= (*x
)->region()->first_frame();
539 /* 2. figure out the boundaries for our search for new objects */
541 switch (clicked_regionview
->region()->coverage (first_frame
, last_frame
)) {
543 if (last_frame
< clicked_regionview
->region()->first_frame()) {
544 first_frame
= last_frame
;
545 last_frame
= clicked_regionview
->region()->last_frame();
547 last_frame
= first_frame
;
548 first_frame
= clicked_regionview
->region()->first_frame();
552 case OverlapExternal
:
553 if (last_frame
< clicked_regionview
->region()->first_frame()) {
554 first_frame
= last_frame
;
555 last_frame
= clicked_regionview
->region()->last_frame();
557 last_frame
= first_frame
;
558 first_frame
= clicked_regionview
->region()->first_frame();
562 case OverlapInternal
:
563 if (last_frame
< clicked_regionview
->region()->first_frame()) {
564 first_frame
= last_frame
;
565 last_frame
= clicked_regionview
->region()->last_frame();
567 last_frame
= first_frame
;
568 first_frame
= clicked_regionview
->region()->first_frame();
574 /* nothing to do except add clicked region to selection, since it
575 overlaps with the existing selection in this track.
582 /* click in a track that has no regions selected, so extend vertically
583 to pick out all regions that are defined by the existing selection
588 first_frame
= entered_regionview
->region()->position();
589 last_frame
= entered_regionview
->region()->last_frame();
591 for (RegionSelection::iterator i
= selection
->regions
.begin(); i
!= selection
->regions
.end(); ++i
) {
592 if ((*i
)->region()->position() < first_frame
) {
593 first_frame
= (*i
)->region()->position();
595 if ((*i
)->region()->last_frame() + 1 > last_frame
) {
596 last_frame
= (*i
)->region()->last_frame();
601 /* 2. find all the tracks we should select in */
603 set
<RouteTimeAxisView
*> relevant_tracks
;
605 for (TrackSelection::iterator i
= selection
->tracks
.begin(); i
!= selection
->tracks
.end(); ++i
) {
606 RouteTimeAxisView
* r
= dynamic_cast<RouteTimeAxisView
*> (*i
);
608 relevant_tracks
.insert (r
);
612 set
<RouteTimeAxisView
*> already_in_selection
;
614 if (relevant_tracks
.empty()) {
616 /* no tracks selected .. thus .. if the
617 regionview we're in isn't selected
618 (i.e. we're about to extend to it), then
619 find all tracks between the this one and
623 if (!selection
->selected (entered_regionview
)) {
625 RouteTimeAxisView
* rtv
= dynamic_cast<RouteTimeAxisView
*> (&entered_regionview
->get_time_axis_view());
629 /* add this track to the ones we will search */
631 relevant_tracks
.insert (rtv
);
633 /* find the track closest to this one that
634 already a selected region.
637 RouteTimeAxisView
* closest
= 0;
638 int distance
= INT_MAX
;
639 int key
= rtv
->route()->order_key ("editor");
641 for (RegionSelection::iterator x
= selection
->regions
.begin(); x
!= selection
->regions
.end(); ++x
) {
643 RouteTimeAxisView
* artv
= dynamic_cast<RouteTimeAxisView
*>(&(*x
)->get_time_axis_view());
645 if (artv
&& artv
!= rtv
) {
647 pair
<set
<RouteTimeAxisView
*>::iterator
,bool> result
;
649 result
= already_in_selection
.insert (artv
);
652 /* newly added to already_in_selection */
654 int d
= artv
->route()->order_key ("editor");
658 if (abs (d
) < distance
) {
668 /* now add all tracks between that one and this one */
670 int okey
= closest
->route()->order_key ("editor");
676 for (TrackViewList::iterator x
= track_views
.begin(); x
!= track_views
.end(); ++x
) {
677 RouteTimeAxisView
* artv
= dynamic_cast<RouteTimeAxisView
*>(*x
);
678 if (artv
&& artv
!= rtv
) {
680 int k
= artv
->route()->order_key ("editor");
682 if (k
>= okey
&& k
<= key
) {
684 /* in range but don't add it if
685 it already has tracks selected.
686 this avoids odd selection
687 behaviour that feels wrong.
690 if (find (already_in_selection
.begin(),
691 already_in_selection
.end(),
692 artv
) == already_in_selection
.end()) {
694 relevant_tracks
.insert (artv
);
704 /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
705 one that was clicked.
708 for (set
<RouteTimeAxisView
*>::iterator t
= relevant_tracks
.begin(); t
!= relevant_tracks
.end(); ++t
) {
709 (*t
)->get_selectables (first_frame
, last_frame
, -1.0, -1.0, results
);
712 /* 4. convert to a vector of regions */
714 vector
<RegionView
*> regions
;
716 for (list
<Selectable
*>::iterator x
= results
.begin(); x
!= results
.end(); ++x
) {
719 if ((arv
= dynamic_cast<RegionView
*>(*x
)) != 0) {
720 regions
.push_back (arv
);
724 if (!regions
.empty()) {
725 selection
->add (regions
);
736 Editor::set_selected_regionview_from_region_list (boost::shared_ptr
<Region
> region
, Selection::Operation op
)
738 vector
<RegionView
*> all_equivalent_regions
;
740 get_regions_corresponding_to (region
, all_equivalent_regions
);
742 if (all_equivalent_regions
.empty()) {
746 begin_reversible_command (_("set selected regions"));
749 case Selection::Toggle
:
750 /* XXX this is not correct */
751 selection
->toggle (all_equivalent_regions
);
754 selection
->set (all_equivalent_regions
);
756 case Selection::Extend
:
757 selection
->add (all_equivalent_regions
);
760 selection
->add (all_equivalent_regions
);
764 commit_reversible_command () ;
768 Editor::set_selected_regionview_from_map_event (GdkEventAny
* /*ev*/, StreamView
* sv
, boost::weak_ptr
<Region
> weak_r
)
771 boost::shared_ptr
<Region
> r (weak_r
.lock());
777 if ((rv
= sv
->find_view (r
)) == 0) {
781 /* don't reset the selection if its something other than
782 a single other region.
785 if (selection
->regions
.size() > 1) {
789 begin_reversible_command (_("set selected regions"));
793 commit_reversible_command () ;
799 Editor::track_selection_changed ()
801 switch (selection
->tracks
.size()){
805 set_selected_mixer_strip (*(selection
->tracks
.front()));
809 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
810 if (find (selection
->tracks
.begin(), selection
->tracks
.end(), *i
) != selection
->tracks
.end()) {
811 (*i
)->set_selected (true);
813 (*i
)->set_selected (false);
817 ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions
, !selection
->tracks
.empty());
821 Editor::time_selection_changed ()
823 if (Profile
->get_sae()) {
827 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
828 (*i
)->hide_selection ();
831 for (TrackSelection::iterator i
= selection
->tracks
.begin(); i
!= selection
->tracks
.end(); ++i
) {
832 (*i
)->show_selection (selection
->time
);
835 if (selection
->time
.empty()) {
836 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions
, false);
838 ActionManager::set_sensitive (ActionManager::time_selection_sensitive_actions
, true);
843 Editor::sensitize_the_right_region_actions (bool have_selected_regions
)
845 for (vector
<Glib::RefPtr
<Action
> >::iterator x
= ActionManager::region_selection_sensitive_actions
.begin();
846 x
!= ActionManager::region_selection_sensitive_actions
.end(); ++x
) {
848 string accel_path
= (*x
)->get_accel_path ();
851 /* if there is an accelerator, it should always be sensitive
852 to allow for keyboard ops on entered regions.
855 bool known
= ActionManager::lookup_entry (accel_path
, key
);
857 if (known
&& ((key
.get_key() != GDK_VoidSymbol
) && (key
.get_key() != 0))) {
858 (*x
)->set_sensitive (true);
860 (*x
)->set_sensitive (have_selected_regions
);
867 Editor::region_selection_changed ()
869 _regions
->block_change_connection (true);
870 editor_regions_selection_changed_connection
.block(true);
872 _regions
->unselect_all ();
874 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
875 (*i
)->set_selected_regionviews (selection
->regions
);
878 _regions
->set_selected (selection
->regions
);
880 sensitize_the_right_region_actions (!selection
->regions
.empty());
882 _regions
->block_change_connection (false);
883 editor_regions_selection_changed_connection
.block(false);
887 Editor::point_selection_changed ()
889 for (TrackViewList::iterator i
= track_views
.begin(); i
!= track_views
.end(); ++i
) {
890 (*i
)->set_selected_points (selection
->points
);
895 Editor::select_all_in_track (Selection::Operation op
)
897 list
<Selectable
*> touched
;
899 if (!clicked_routeview
) {
903 clicked_routeview
->get_selectables (0, max_frames
, 0, DBL_MAX
, touched
);
906 case Selection::Toggle
:
907 selection
->add (touched
);
910 selection
->set (touched
);
912 case Selection::Extend
:
913 /* meaningless, because we're selecting everything */
916 selection
->add (touched
);
922 Editor::select_all (Selection::Operation op
)
924 list
<Selectable
*> touched
;
926 for (TrackViewList::iterator iter
= track_views
.begin(); iter
!= track_views
.end(); ++iter
) {
927 if ((*iter
)->hidden()) {
930 (*iter
)->get_selectables (0, max_frames
, 0, DBL_MAX
, touched
);
932 begin_reversible_command (_("select all"));
935 selection
->add (touched
);
937 case Selection::Toggle
:
938 selection
->add (touched
);
941 selection
->set (touched
);
943 case Selection::Extend
:
944 /* meaningless, because we're selecting everything */
947 commit_reversible_command ();
950 Editor::invert_selection_in_track ()
952 list
<Selectable
*> touched
;
954 if (!clicked_routeview
) {
958 clicked_routeview
->get_inverted_selectables (*selection
, touched
);
959 selection
->set (touched
);
963 Editor::invert_selection ()
965 list
<Selectable
*> touched
;
967 for (TrackViewList::iterator iter
= track_views
.begin(); iter
!= track_views
.end(); ++iter
) {
968 if ((*iter
)->hidden()) {
971 (*iter
)->get_inverted_selectables (*selection
, touched
);
974 selection
->set (touched
);
977 /** @param top Top (lower) y limit in trackview coordinates.
978 * @param bottom Bottom (higher) y limit in trackview coordinates.
981 Editor::select_all_within (nframes64_t start
, nframes64_t end
, double top
, double bot
, const TrackViewList
& tracklist
, Selection::Operation op
)
983 list
<Selectable
*> found
;
985 for (TrackViewList::const_iterator iter
= tracklist
.begin(); iter
!= tracklist
.end(); ++iter
) {
987 if ((*iter
)->hidden()) {
991 (*iter
)->get_selectables (start
, end
, top
, bot
, found
);
998 begin_reversible_command (_("select all within"));
1000 case Selection::Add
:
1001 selection
->add (found
);
1003 case Selection::Toggle
:
1004 selection
->toggle (found
);
1006 case Selection::Set
:
1007 selection
->set (found
);
1009 case Selection::Extend
:
1010 /* not defined yet */
1014 commit_reversible_command ();
1016 return !found
.empty();
1020 Editor::set_selection_from_region ()
1022 if (selection
->regions
.empty()) {
1026 selection
->set (selection
->regions
.start(), selection
->regions
.end_frame());
1027 if (!Profile
->get_sae()) {
1028 set_mouse_mode (Editing::MouseRange
, false);
1033 Editor::set_selection_from_punch()
1037 if ((location
= _session
->locations()->auto_punch_location()) == 0) {
1041 set_selection_from_range (*location
);
1045 Editor::set_selection_from_loop()
1049 if ((location
= _session
->locations()->auto_loop_location()) == 0) {
1052 set_selection_from_range (*location
);
1056 Editor::set_selection_from_range (Location
& loc
)
1058 begin_reversible_command (_("set selection from range"));
1059 selection
->set (loc
.start(), loc
.end());
1060 commit_reversible_command ();
1062 if (!Profile
->get_sae()) {
1063 set_mouse_mode (Editing::MouseRange
, false);
1068 Editor::select_all_selectables_using_time_selection ()
1070 list
<Selectable
*> touched
;
1072 if (selection
->time
.empty()) {
1076 nframes64_t start
= selection
->time
[clicked_selection
].start
;
1077 nframes64_t end
= selection
->time
[clicked_selection
].end
;
1079 if (end
- start
< 1) {
1085 if (selection
->tracks
.empty()) {
1088 ts
= &selection
->tracks
;
1091 for (TrackViewList::iterator iter
= ts
->begin(); iter
!= ts
->end(); ++iter
) {
1092 if ((*iter
)->hidden()) {
1095 (*iter
)->get_selectables (start
, end
- 1, 0, DBL_MAX
, touched
);
1098 begin_reversible_command (_("select all from range"));
1099 selection
->set (touched
);
1100 commit_reversible_command ();
1105 Editor::select_all_selectables_using_punch()
1107 Location
* location
= _session
->locations()->auto_punch_location();
1108 list
<Selectable
*> touched
;
1110 if (location
== 0 || (location
->end() - location
->start() <= 1)) {
1117 if (selection
->tracks
.empty()) {
1120 ts
= &selection
->tracks
;
1123 for (TrackViewList::iterator iter
= ts
->begin(); iter
!= ts
->end(); ++iter
) {
1124 if ((*iter
)->hidden()) {
1127 (*iter
)->get_selectables (location
->start(), location
->end() - 1, 0, DBL_MAX
, touched
);
1129 begin_reversible_command (_("select all from punch"));
1130 selection
->set (touched
);
1131 commit_reversible_command ();
1136 Editor::select_all_selectables_using_loop()
1138 Location
* location
= _session
->locations()->auto_loop_location();
1139 list
<Selectable
*> touched
;
1141 if (location
== 0 || (location
->end() - location
->start() <= 1)) {
1148 if (selection
->tracks
.empty()) {
1151 ts
= &selection
->tracks
;
1154 for (TrackViewList::iterator iter
= ts
->begin(); iter
!= ts
->end(); ++iter
) {
1155 if ((*iter
)->hidden()) {
1158 (*iter
)->get_selectables (location
->start(), location
->end() - 1, 0, DBL_MAX
, touched
);
1160 begin_reversible_command (_("select all from loop"));
1161 selection
->set (touched
);
1162 commit_reversible_command ();
1167 Editor::select_all_selectables_using_cursor (EditorCursor
*cursor
, bool after
)
1171 list
<Selectable
*> touched
;
1174 begin_reversible_command (_("select all after cursor"));
1175 start
= cursor
->current_frame
;
1176 end
= _session
->current_end_frame();
1178 if (cursor
->current_frame
> 0) {
1179 begin_reversible_command (_("select all before cursor"));
1181 end
= cursor
->current_frame
- 1;
1190 if (selection
->tracks
.empty()) {
1193 ts
= &selection
->tracks
;
1196 for (TrackViewList::iterator iter
= ts
->begin(); iter
!= ts
->end(); ++iter
) {
1197 if ((*iter
)->hidden()) {
1200 (*iter
)->get_selectables (start
, end
, 0, DBL_MAX
, touched
);
1202 selection
->set (touched
);
1203 commit_reversible_command ();
1207 Editor::select_all_selectables_using_edit (bool after
)
1211 list
<Selectable
*> touched
;
1214 begin_reversible_command (_("select all after edit"));
1215 start
= get_preferred_edit_position();
1216 end
= _session
->current_end_frame();
1218 if ((end
= get_preferred_edit_position()) > 1) {
1219 begin_reversible_command (_("select all before edit"));
1230 if (selection
->tracks
.empty()) {
1233 ts
= &selection
->tracks
;
1236 for (TrackViewList::iterator iter
= ts
->begin(); iter
!= ts
->end(); ++iter
) {
1237 if ((*iter
)->hidden()) {
1240 (*iter
)->get_selectables (start
, end
, 0, DBL_MAX
, touched
);
1242 selection
->set (touched
);
1243 commit_reversible_command ();
1247 Editor::select_all_selectables_between (bool /*within*/)
1251 list
<Selectable
*> touched
;
1253 if (!get_edit_op_range (start
, end
)) {
1259 if (selection
->tracks
.empty()) {
1262 ts
= &selection
->tracks
;
1265 for (TrackViewList::iterator iter
= ts
->begin(); iter
!= ts
->end(); ++iter
) {
1266 if ((*iter
)->hidden()) {
1269 (*iter
)->get_selectables (start
, end
, 0, DBL_MAX
, touched
);
1272 selection
->set (touched
);
1276 Editor::select_range_between ()
1281 if (!get_edit_op_range (start
, end
)) {
1285 set_mouse_mode (MouseRange
);
1286 selection
->set (start
, end
);
1290 Editor::get_edit_op_range (nframes64_t
& start
, nframes64_t
& end
) const
1295 /* in range mode, use any existing selection */
1297 if (mouse_mode
== MouseRange
&& !selection
->time
.empty()) {
1298 /* we know that these are ordered */
1299 start
= selection
->time
.start();
1300 end
= selection
->time
.end_frame();
1304 if (!mouse_frame (m
, ignored
)) {
1305 /* mouse is not in a canvas, try playhead+selected marker.
1306 this is probably most true when using menus.
1309 if (selection
->markers
.empty()) {
1313 start
= selection
->markers
.front()->position();
1314 end
= _session
->audible_frame();
1318 switch (_edit_point
) {
1319 case EditAtPlayhead
:
1320 if (selection
->markers
.empty()) {
1321 /* use mouse + playhead */
1323 end
= _session
->audible_frame();
1325 /* use playhead + selected marker */
1326 start
= _session
->audible_frame();
1327 end
= selection
->markers
.front()->position();
1332 /* use mouse + selected marker */
1333 if (selection
->markers
.empty()) {
1335 end
= _session
->audible_frame();
1337 start
= selection
->markers
.front()->position();
1342 case EditAtSelectedMarker
:
1343 /* use mouse + selected marker */
1344 if (selection
->markers
.empty()) {
1346 MessageDialog
win (_("No edit range defined"),
1351 win
.set_secondary_text (
1352 _("the edit point is Selected Marker\nbut there is no selected marker."));
1355 win
.set_default_response (RESPONSE_CLOSE
);
1356 win
.set_position (Gtk::WIN_POS_MOUSE
);
1361 return false; // NO RANGE
1363 start
= selection
->markers
.front()->position();
1377 /* turn range into one delimited by start...end,
1387 Editor::deselect_all ()
1389 selection
->clear ();
1393 Editor::select_range_around_region (RegionView
* rv
)
1397 selection
->set (&rv
->get_time_axis_view());
1399 selection
->time
.clear ();
1400 boost::shared_ptr
<Region
> r
= rv
->region ();
1401 return selection
->set (r
->position(), r
->position() + r
->length());