ardour
editor_selection.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2000-2006 Paul Davis
3 
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.
8 
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.
13 
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.
17 
18 */
19 
20 #include <algorithm>
21 #include <cstdlib>
22 
23 #include "pbd/stacktrace.h"
24 
25 #include "ardour/midi_region.h"
26 #include "ardour/playlist.h"
27 #include "ardour/profile.h"
28 #include "ardour/route_group.h"
29 #include "ardour/session.h"
30 
31 #include "control_protocol/control_protocol.h"
32 
33 #include "editor.h"
34 #include "actions.h"
35 #include "audio_time_axis.h"
36 #include "audio_region_view.h"
37 #include "audio_streamview.h"
38 #include "automation_line.h"
39 #include "control_point.h"
40 #include "editor_regions.h"
41 #include "editor_cursors.h"
42 #include "midi_region_view.h"
43 
44 #include "i18n.h"
45 
46 using namespace std;
47 using namespace ARDOUR;
48 using namespace PBD;
49 using namespace Gtk;
50 using namespace Glib;
51 using namespace Gtkmm2ext;
52 using namespace Editing;
53 
55 {
56  bool operator() (const TimeAxisView* a, const TimeAxisView *b) {
57  return a->y_position() < b->y_position();
58  }
59 };
60 
61 bool
63 {
64  if (selection->selected (&view)) {
65  /* already selected, do nothing */
66  return false;
67  }
68 
69  if (selection->tracks.empty()) {
70 
71  if (!selection->selected (&view)) {
72  selection->set (&view);
73  return true;
74  } else {
75  return false;
76  }
77  }
78 
79  /* something is already selected, so figure out which range of things to add */
80 
81  TrackViewList to_be_added;
82  TrackViewList sorted = track_views;
84  bool passed_clicked = false;
85  bool forwards = true;
86 
87  sorted.sort (cmp);
88 
89  if (!selection->selected (&view)) {
90  to_be_added.push_back (&view);
91  }
92 
93  /* figure out if we should go forward or backwards */
94 
95  for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
96 
97  if ((*i) == &view) {
98  passed_clicked = true;
99  }
100 
101  if (selection->selected (*i)) {
102  if (passed_clicked) {
103  forwards = true;
104  } else {
105  forwards = false;
106  }
107  break;
108  }
109  }
110 
111  passed_clicked = false;
112 
113  if (forwards) {
114 
115  for (TrackViewList::iterator i = sorted.begin(); i != sorted.end(); ++i) {
116 
117  if ((*i) == &view) {
118  passed_clicked = true;
119  continue;
120  }
121 
122  if (passed_clicked) {
123  if ((*i)->hidden()) {
124  continue;
125  }
126  if (selection->selected (*i)) {
127  break;
128  } else if (!(*i)->hidden()) {
129  to_be_added.push_back (*i);
130  }
131  }
132  }
133 
134  } else {
135 
136  for (TrackViewList::reverse_iterator r = sorted.rbegin(); r != sorted.rend(); ++r) {
137 
138  if ((*r) == &view) {
139  passed_clicked = true;
140  continue;
141  }
142 
143  if (passed_clicked) {
144 
145  if ((*r)->hidden()) {
146  continue;
147  }
148 
149  if (selection->selected (*r)) {
150  break;
151  } else if (!(*r)->hidden()) {
152  to_be_added.push_back (*r);
153  }
154  }
155  }
156  }
157 
158  if (!to_be_added.empty()) {
159  selection->add (to_be_added);
160  return true;
161  }
162 
163  return false;
164 }
165 
166 void
168 {
169  TrackViewList visible_views;
170  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
171  if ((*i)->marked_for_display()) {
172  visible_views.push_back (*i);
173  }
174  }
175  selection->set (visible_views);
176 }
177 
181 void
183 {
184  if (!clicked_axisview) {
185  return;
186  }
187 
188  RouteGroup* group = NULL;
189  if (clicked_routeview) {
190  group = clicked_routeview->route()->route_group();
191  }
192 
193  bool had_tracks = !selection->tracks.empty();
194  RouteGroup& arg (_session->all_route_group());
195 
196  switch (op) {
197  case Selection::Toggle:
198  if (selection->selected (clicked_axisview)) {
199  if (arg.is_select() && arg.is_active()) {
200  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
201  selection->remove(*i);
202  }
203  } else if (group && group->is_active()) {
204  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
205  if ((*i)->route_group() == group) {
206  selection->remove(*i);
207  }
208  }
209  } else {
210  selection->remove (clicked_axisview);
211  }
212  } else {
213  if (arg.is_select() && arg.is_active()) {
214  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
215  selection->add(*i);
216  }
217  } else if (group && group->is_active()) {
218  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
219  if ((*i)->route_group() == group) {
220  selection->add(*i);
221  }
222  }
223  } else {
224  selection->add (clicked_axisview);
225  }
226  }
227  break;
228 
229  case Selection::Add:
230  if (!had_tracks && arg.is_select() && arg.is_active()) {
231  /* nothing was selected already, and all group is active etc. so use
232  all tracks.
233  */
234  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
235  selection->add(*i);
236  }
237  } else if (group && group->is_active()) {
238  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
239  if ((*i)->route_group() == group) {
240  selection->add(*i);
241  }
242  }
243  } else {
244  selection->add (clicked_axisview);
245  }
246  break;
247 
248  case Selection::Set:
249  selection->clear();
250  if (!had_tracks && arg.is_select() && arg.is_active()) {
251  /* nothing was selected already, and all group is active etc. so use
252  all tracks.
253  */
254  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
255  selection->add(*i);
256  }
257  } else if (group && group->is_active()) {
258  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
259  if ((*i)->route_group() == group) {
260  selection->add(*i);
261  }
262  }
263  } else {
264  selection->set (clicked_axisview);
265  }
266  break;
267 
268  case Selection::Extend:
269  selection->clear();
270  break;
271  }
272 }
273 
274 void
276 {
277  begin_reversible_selection_op (X_("Set Selected Track"));
278 
279  switch (op) {
280  case Selection::Toggle:
281  if (selection->selected (&view)) {
282  if (!no_remove) {
283  selection->remove (&view);
284  }
285  } else {
286  selection->add (&view);
287  }
288  break;
289 
290  case Selection::Add:
291  if (!selection->selected (&view)) {
292  selection->add (&view);
293  }
294  break;
295 
296  case Selection::Set:
297  selection->set (&view);
298  break;
299 
300  case Selection::Extend:
301  extend_selection_to_track (view);
302  break;
303  }
304 
305  commit_reversible_selection_op ();
306 }
307 
308 void
310 {
311  if (!clicked_routeview) {
312  return;
313  }
314 
315  if (!press) {
316  return;
317  }
318 
319  set_selected_track (*clicked_routeview, op, no_remove);
320 }
321 
322 bool
324 {
325  if (!clicked_control_point) {
326  return false;
327  }
328 
329  switch (op) {
330  case Selection::Set:
331  if (press) {
332  selection->set (clicked_control_point);
333  }
334  break;
335  case Selection::Add:
336  if (press) {
337  selection->add (clicked_control_point);
338  }
339  break;
340  case Selection::Toggle:
341  /* This is a bit of a hack; if we Primary-Click-Drag a control
342  point (for push drag) we want the point we clicked on to be
343  selected, otherwise we end up confusingly dragging an
344  unselected point. So here we ensure that the point is selected
345  after the press, and if we subsequently get a release (meaning no
346  drag occurred) we set things up so that the toggle has happened.
347  */
348  if (press && !selection->selected (clicked_control_point)) {
349  /* This is the button press, and the control point is not selected; make it so,
350  in case this press leads to a drag. Also note that having done this, we don't
351  need to toggle again on release.
352  */
353  selection->toggle (clicked_control_point);
354  _control_point_toggled_on_press = true;
355  } else if (!press && !_control_point_toggled_on_press) {
356  /* This is the release, and the point wasn't toggled on the press, so do it now */
357  selection->toggle (clicked_control_point);
358  } else {
359  /* Reset our flag */
360  _control_point_toggled_on_press = false;
361  }
362  break;
363  case Selection::Extend:
364  /* XXX */
365  break;
366  }
367 
368  return true;
369 }
370 
371 void
373 {
374  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
375  if ((*i)->y_position() < _visible_canvas_height) {
376  tvl.push_back (*i);
377  }
378  }
379 }
380 
389 void
390 Editor::mapover_tracks (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
391 {
392  RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
393 
394  if (route_basis == 0) {
395  return;
396  }
397 
398  set<RouteTimeAxisView*> tracks;
399  tracks.insert (route_basis);
400 
401  RouteGroup* group = route_basis->route()->route_group();
402 
403  if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id) ) {
404 
405  /* the basis is a member of an active route group, with the appropriate
406  properties; find other members */
407 
408  for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
409  RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
410  if (v && v->route()->route_group() == group) {
411  tracks.insert (v);
412  }
413  }
414  }
415 
416  /* call the slots */
417  uint32_t const sz = tracks.size ();
418 
419  for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
420  sl (**i, sz);
421  }
422 }
423 
432 void
433 Editor::mapover_tracks_with_unique_playlists (sigc::slot<void, RouteTimeAxisView&, uint32_t> sl, TimeAxisView* basis, PBD::PropertyID prop) const
434 {
435  RouteTimeAxisView* route_basis = dynamic_cast<RouteTimeAxisView*> (basis);
436  set<boost::shared_ptr<Playlist> > playlists;
437 
438  if (route_basis == 0) {
439  return;
440  }
441 
442  set<RouteTimeAxisView*> tracks;
443  tracks.insert (route_basis);
444 
445  RouteGroup* group = route_basis->route()->route_group(); // could be null, not a problem
446 
447  if (group && group->enabled_property(prop) && group->enabled_property (Properties::active.property_id) ) {
448 
449  /* the basis is a member of an active route group, with the appropriate
450  properties; find other members */
451 
452  for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
453  RouteTimeAxisView* v = dynamic_cast<RouteTimeAxisView*> (*i);
454 
455  if (v && v->route()->route_group() == group) {
456 
458  if (t) {
459  if (playlists.insert (t->playlist()).second) {
460  /* haven't seen this playlist yet */
461  tracks.insert (v);
462  }
463  } else {
464  /* not actually a "Track", but a timeaxis view that
465  we should mapover anyway.
466  */
467  tracks.insert (v);
468  }
469  }
470  }
471  }
472 
473  /* call the slots */
474  uint32_t const sz = tracks.size ();
475 
476  for (set<RouteTimeAxisView*>::iterator i = tracks.begin(); i != tracks.end(); ++i) {
477  sl (**i, sz);
478  }
479 }
480 
481 void
482 Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionView * basis, vector<RegionView*>* all_equivs) const
483 {
485  vector<boost::shared_ptr<Region> > results;
486  RegionView* marv;
488 
489  if ((tr = tv.track()) == 0) {
490  /* bus */
491  return;
492  }
493 
494  if (&tv == &basis->get_time_axis_view()) {
495  /* looking in same track as the original */
496  return;
497  }
498 
499  if ((pl = tr->playlist()) != 0) {
500  pl->get_equivalent_regions (basis->region(), results);
501  }
502 
503  for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
504  if ((marv = tv.view()->find_view (*ir)) != 0) {
505  all_equivs->push_back (marv);
506  }
507  }
508 }
509 
510 void
511 Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, PBD::PropertyID property) const
512 {
513  mapover_tracks_with_unique_playlists (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_time_axis_view(), property);
514 
515  /* add clicked regionview since we skipped all other regions in the same track as the one it was in */
516 
517  equivalent_regions.push_back (basis);
518 }
519 
522 {
523  RegionSelection equivalent;
524 
525  for (RegionSelection::const_iterator i = basis.begin(); i != basis.end(); ++i) {
526 
527  vector<RegionView*> eq;
528 
529  mapover_tracks_with_unique_playlists (
530  sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq),
531  &(*i)->get_time_axis_view(), prop);
532 
533  for (vector<RegionView*>::iterator j = eq.begin(); j != eq.end(); ++j) {
534  equivalent.add (*j);
535  }
536 
537  equivalent.add (*i);
538  }
539 
540  return equivalent;
541 }
542 
543 int
545 {
546  int region_count = 0;
547 
548  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
549 
550  RouteTimeAxisView* tatv;
551 
552  if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
553 
555  vector<boost::shared_ptr<Region> > results;
556  RegionView* marv;
558 
559  if ((tr = tatv->track()) == 0) {
560  /* bus */
561  continue;
562  }
563 
564  if ((pl = (tr->playlist())) != 0) {
565  pl->get_region_list_equivalent_regions (region, results);
566  }
567 
568  for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
569  if ((marv = tatv->view()->find_view (*ir)) != 0) {
570  region_count++;
571  }
572  }
573 
574  }
575  }
576 
577  return region_count;
578 }
579 
580 
581 bool
583 {
584  vector<RegionView*> all_equivalent_regions;
585  bool commit = false;
586 
587  if (!clicked_regionview || !clicked_routeview) {
588  return false;
589  }
590 
591  if (press) {
592  button_release_can_deselect = false;
593  }
594 
595  if (op == Selection::Toggle || op == Selection::Set) {
596 
597  switch (op) {
598  case Selection::Toggle:
599  if (selection->selected (clicked_regionview)) {
600  if (press) {
601 
602  /* whatever was clicked was selected already; do nothing here but allow
603  the button release to deselect it
604  */
605 
606  button_release_can_deselect = true;
607 
608  } else {
609  if (button_release_can_deselect) {
610 
611  /* just remove this one region, but only on a permitted button release */
612 
613  selection->remove (clicked_regionview);
614  commit = true;
615 
616  /* no more deselect action on button release till a new press
617  finds an already selected object.
618  */
619 
620  button_release_can_deselect = false;
621  }
622  }
623 
624  } else {
625 
626  if (press) {
627 
628  if (selection->selected (clicked_routeview)) {
629  get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
630  } else {
631  all_equivalent_regions.push_back (clicked_regionview);
632  }
633 
634  /* add all the equivalent regions, but only on button press */
635 
636  if (!all_equivalent_regions.empty()) {
637  commit = true;
638  }
639 
640  selection->add (all_equivalent_regions);
641  }
642  }
643  break;
644 
645  case Selection::Set:
646  if (!selection->selected (clicked_regionview)) {
647  get_equivalent_regions (clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
648  selection->set (all_equivalent_regions);
649  commit = true;
650  } else {
651  /* clicked on an already selected region */
652  if (press)
653  goto out;
654  else {
655  get_equivalent_regions(clicked_regionview, all_equivalent_regions, ARDOUR::Properties::select.property_id);
656  selection->set(all_equivalent_regions);
657  commit = true;
658  }
659  }
660  break;
661 
662  default:
663  /* silly compiler */
664  break;
665  }
666 
667  } else if (op == Selection::Extend) {
668 
669  list<Selectable*> results;
670  framepos_t last_frame;
671  framepos_t first_frame;
672  bool same_track = false;
673 
674  /* 1. find the last selected regionview in the track that was clicked in */
675 
676  last_frame = 0;
677  first_frame = max_framepos;
678 
679  for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
680  if (&(*x)->get_time_axis_view() == &clicked_regionview->get_time_axis_view()) {
681 
682  if ((*x)->region()->last_frame() > last_frame) {
683  last_frame = (*x)->region()->last_frame();
684  }
685 
686  if ((*x)->region()->first_frame() < first_frame) {
687  first_frame = (*x)->region()->first_frame();
688  }
689 
690  same_track = true;
691  }
692  }
693 
694  if (same_track) {
695 
696  /* 2. figure out the boundaries for our search for new objects */
697 
698  switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
699  case Evoral::OverlapNone:
700  if (last_frame < clicked_regionview->region()->first_frame()) {
701  first_frame = last_frame;
702  last_frame = clicked_regionview->region()->last_frame();
703  } else {
704  last_frame = first_frame;
705  first_frame = clicked_regionview->region()->first_frame();
706  }
707  break;
708 
710  if (last_frame < clicked_regionview->region()->first_frame()) {
711  first_frame = last_frame;
712  last_frame = clicked_regionview->region()->last_frame();
713  } else {
714  last_frame = first_frame;
715  first_frame = clicked_regionview->region()->first_frame();
716  }
717  break;
718 
720  if (last_frame < clicked_regionview->region()->first_frame()) {
721  first_frame = last_frame;
722  last_frame = clicked_regionview->region()->last_frame();
723  } else {
724  last_frame = first_frame;
725  first_frame = clicked_regionview->region()->first_frame();
726  }
727  break;
728 
730  case Evoral::OverlapEnd:
731  /* nothing to do except add clicked region to selection, since it
732  overlaps with the existing selection in this track.
733  */
734  break;
735  }
736 
737  } else {
738 
739  /* click in a track that has no regions selected, so extend vertically
740  to pick out all regions that are defined by the existing selection
741  plus this one.
742  */
743 
744 
745  first_frame = clicked_regionview->region()->position();
746  last_frame = clicked_regionview->region()->last_frame();
747 
748  for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
749  if ((*i)->region()->position() < first_frame) {
750  first_frame = (*i)->region()->position();
751  }
752  if ((*i)->region()->last_frame() + 1 > last_frame) {
753  last_frame = (*i)->region()->last_frame();
754  }
755  }
756  }
757 
758  /* 2. find all the tracks we should select in */
759 
760  set<RouteTimeAxisView*> relevant_tracks;
761 
762  for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
763  RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
764  if (r) {
765  relevant_tracks.insert (r);
766  }
767  }
768 
769  set<RouteTimeAxisView*> already_in_selection;
770 
771  if (relevant_tracks.empty()) {
772 
773  /* no tracks selected .. thus .. if the
774  regionview we're in isn't selected
775  (i.e. we're about to extend to it), then
776  find all tracks between the this one and
777  any selected ones.
778  */
779 
780  if (!selection->selected (clicked_regionview)) {
781 
782  RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&clicked_regionview->get_time_axis_view());
783 
784  if (rtv) {
785 
786  /* add this track to the ones we will search */
787 
788  relevant_tracks.insert (rtv);
789 
790  /* find the track closest to this one that
791  already a selected region.
792  */
793 
794  RouteTimeAxisView* closest = 0;
795  int distance = INT_MAX;
796  int key = rtv->route()->order_key ();
797 
798  for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
799 
800  RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(&(*x)->get_time_axis_view());
801 
802  if (artv && artv != rtv) {
803 
804  pair<set<RouteTimeAxisView*>::iterator,bool> result;
805 
806  result = already_in_selection.insert (artv);
807 
808  if (result.second) {
809  /* newly added to already_in_selection */
810 
811  int d = artv->route()->order_key ();
812 
813  d -= key;
814 
815  if (abs (d) < distance) {
816  distance = abs (d);
817  closest = artv;
818  }
819  }
820  }
821  }
822 
823  if (closest) {
824 
825  /* now add all tracks between that one and this one */
826 
827  int okey = closest->route()->order_key ();
828 
829  if (okey > key) {
830  swap (okey, key);
831  }
832 
833  for (TrackViewList::iterator x = track_views.begin(); x != track_views.end(); ++x) {
834  RouteTimeAxisView* artv = dynamic_cast<RouteTimeAxisView*>(*x);
835  if (artv && artv != rtv) {
836 
837  int k = artv->route()->order_key ();
838 
839  if (k >= okey && k <= key) {
840 
841  /* in range but don't add it if
842  it already has tracks selected.
843  this avoids odd selection
844  behaviour that feels wrong.
845  */
846 
847  if (find (already_in_selection.begin(),
848  already_in_selection.end(),
849  artv) == already_in_selection.end()) {
850 
851  relevant_tracks.insert (artv);
852  }
853  }
854  }
855  }
856  }
857  }
858  }
859  }
860 
861  /* 3. find all selectable objects (regionviews in this case) between that one and the end of the
862  one that was clicked.
863  */
864 
865  for (set<RouteTimeAxisView*>::iterator t = relevant_tracks.begin(); t != relevant_tracks.end(); ++t) {
866  (*t)->get_selectables (first_frame, last_frame, -1.0, -1.0, results);
867  }
868 
869  /* 4. convert to a vector of regions */
870 
871  vector<RegionView*> regions;
872 
873  for (list<Selectable*>::iterator x = results.begin(); x != results.end(); ++x) {
874  RegionView* arv;
875 
876  if ((arv = dynamic_cast<RegionView*>(*x)) != 0) {
877  regions.push_back (arv);
878  }
879  }
880 
881  if (!regions.empty()) {
882  selection->add (regions);
883  commit = true;
884  }
885  }
886 
887 out:
888  return commit;
889 }
890 
891 
892 void
894 {
895  vector<RegionView*> all_equivalent_regions;
896 
897  get_regions_corresponding_to (region, all_equivalent_regions, region->whole_file());
898 
899  if (all_equivalent_regions.empty()) {
900  return;
901  }
902 
903  begin_reversible_selection_op (X_("set selected regions"));
904 
905  switch (op) {
906  case Selection::Toggle:
907  /* XXX this is not correct */
908  selection->toggle (all_equivalent_regions);
909  break;
910  case Selection::Set:
911  selection->set (all_equivalent_regions);
912  break;
913  case Selection::Extend:
914  selection->add (all_equivalent_regions);
915  break;
916  case Selection::Add:
917  selection->add (all_equivalent_regions);
918  break;
919  }
920 
921  commit_reversible_selection_op () ;
922 }
923 
924 bool
926 {
927  RegionView* rv;
928  boost::shared_ptr<Region> r (weak_r.lock());
929 
930  if (!r) {
931  return true;
932  }
933 
934  if ((rv = sv->find_view (r)) == 0) {
935  return true;
936  }
937 
938  /* don't reset the selection if its something other than
939  a single other region.
940  */
941 
942  if (selection->regions.size() > 1) {
943  return true;
944  }
945 
946  begin_reversible_selection_op (X_("set selected regions"));
947 
948  selection->set (rv);
949 
950  commit_reversible_selection_op () ;
951 
952  return true;
953 }
954 
955 void
957 {
958  switch (selection->tracks.size()) {
959  case 0:
960  break;
961  default:
962  set_selected_mixer_strip (*(selection->tracks.front()));
963  break;
964  }
965 
966  RouteNotificationListPtr routes (new RouteNotificationList);
967 
968  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
969 
970  bool yn = (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end());
971 
972  (*i)->set_selected (yn);
973 
974  TimeAxisView::Children c = (*i)->get_child_list ();
975  for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
976  (*j)->set_selected (find (selection->tracks.begin(), selection->tracks.end(), j->get()) != selection->tracks.end());
977  }
978 
979  if (yn) {
980  (*i)->reshow_selection (selection->time);
981  } else {
982  (*i)->hide_selection ();
983  }
984 
985 
986  if (yn) {
987  RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*i);
988  if (rtav) {
989  routes->push_back (rtav->route());
990  }
991  }
992  }
993 
995 
996  /* notify control protocols */
997 
998  ControlProtocol::TrackSelectionChanged (routes);
999 }
1000 
1001 void
1003 {
1004  if (Profile->get_sae()) {
1005  return;
1006  }
1007 
1008  /* XXX this is superficially inefficient. Hide the selection in all
1009  * tracks, then show it in all selected tracks.
1010  *
1011  * However, if you investigate what this actually does, it isn't
1012  * anywhere nearly as bad as it may appear. Remember: nothing is
1013  * redrawn or even recomputed during these two loops - that only
1014  * happens when we next render ...
1015  */
1016 
1017  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1018  (*i)->hide_selection ();
1019  }
1020 
1021  for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
1022  (*i)->show_selection (selection->time);
1023  }
1024 
1025  if (selection->time.empty()) {
1027  } else {
1029  }
1030 }
1031 
1033 void
1035 {
1036  Glib::ListHandle<Glib::RefPtr<Action> > all = _region_actions->get_actions ();
1037 
1038  for (Glib::ListHandle<Glib::RefPtr<Action> >::iterator i = all.begin(); i != all.end(); ++i) {
1039  (*i)->set_sensitive (s);
1040  }
1041 
1042  _all_region_actions_sensitized = s;
1043 }
1044 
1053 void
1055 {
1056 
1057  RegionSelection rs = get_regions_from_selection_and_entered ();
1058  sensitize_all_region_actions (!rs.empty ());
1059 
1060  _ignore_region_action = true;
1061 
1062  /* Look through the regions that are selected and make notes about what we have got */
1063 
1064  bool have_audio = false;
1065  bool have_multichannel_audio = false;
1066  bool have_midi = false;
1067  bool have_locked = false;
1068  bool have_unlocked = false;
1069  bool have_video_locked = false;
1070  bool have_video_unlocked = false;
1071  bool have_position_lock_style_audio = false;
1072  bool have_position_lock_style_music = false;
1073  bool have_muted = false;
1074  bool have_unmuted = false;
1075  bool have_opaque = false;
1076  bool have_non_opaque = false;
1077  bool have_not_at_natural_position = false;
1078  bool have_envelope_active = false;
1079  bool have_envelope_inactive = false;
1080  bool have_non_unity_scale_amplitude = false;
1081  bool have_compound_regions = false;
1082  bool have_inactive_fade_in = false;
1083  bool have_inactive_fade_out = false;
1084  bool have_active_fade_in = false;
1085  bool have_active_fade_out = false;
1086 
1087  for (list<RegionView*>::const_iterator i = rs.begin(); i != rs.end(); ++i) {
1088 
1089  boost::shared_ptr<Region> r = (*i)->region ();
1091 
1092  if (ar) {
1093  have_audio = true;
1094  if (ar->n_channels() > 1) {
1095  have_multichannel_audio = true;
1096  }
1097  }
1098 
1099  if (boost::dynamic_pointer_cast<MidiRegion> (r)) {
1100  have_midi = true;
1101  }
1102 
1103  if (r->is_compound()) {
1104  have_compound_regions = true;
1105  }
1106 
1107  if (r->locked()) {
1108  have_locked = true;
1109  } else {
1110  have_unlocked = true;
1111  }
1112 
1113  if (r->video_locked()) {
1114  have_video_locked = true;
1115  } else {
1116  have_video_unlocked = true;
1117  }
1118 
1119  if (r->position_lock_style() == MusicTime) {
1120  have_position_lock_style_music = true;
1121  } else {
1122  have_position_lock_style_audio = true;
1123  }
1124 
1125  if (r->muted()) {
1126  have_muted = true;
1127  } else {
1128  have_unmuted = true;
1129  }
1130 
1131  if (r->opaque()) {
1132  have_opaque = true;
1133  } else {
1134  have_non_opaque = true;
1135  }
1136 
1137  if (!r->at_natural_position()) {
1138  have_not_at_natural_position = true;
1139  }
1140 
1141  if (ar) {
1142  if (ar->envelope_active()) {
1143  have_envelope_active = true;
1144  } else {
1145  have_envelope_inactive = true;
1146  }
1147 
1148  if (ar->scale_amplitude() != 1) {
1149  have_non_unity_scale_amplitude = true;
1150  }
1151 
1152  if (ar->fade_in_active ()) {
1153  have_active_fade_in = true;
1154  } else {
1155  have_inactive_fade_in = true;
1156  }
1157 
1158  if (ar->fade_out_active ()) {
1159  have_active_fade_out = true;
1160  } else {
1161  have_inactive_fade_out = true;
1162  }
1163  }
1164  }
1165 
1166  if (rs.size() > 1) {
1167  _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1168  _region_actions->get_action("show-region-properties")->set_sensitive (false);
1169  _region_actions->get_action("rename-region")->set_sensitive (false);
1170  if (have_audio) {
1171  /* XXX need to check whether there is than 1 per
1172  playlist, because otherwise this makes no sense.
1173  */
1174  _region_actions->get_action("combine-regions")->set_sensitive (true);
1175  } else {
1176  _region_actions->get_action("combine-regions")->set_sensitive (false);
1177  }
1178  } else if (rs.size() == 1) {
1179  _region_actions->get_action("add-range-markers-from-region")->set_sensitive (false);
1180  _region_actions->get_action("close-region-gaps")->set_sensitive (false);
1181  _region_actions->get_action("combine-regions")->set_sensitive (false);
1182  }
1183 
1184  if (!have_multichannel_audio) {
1185  _region_actions->get_action("split-multichannel-region")->set_sensitive (false);
1186  }
1187 
1188  if (!have_midi) {
1189  editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (false);
1190  _region_actions->get_action("show-region-list-editor")->set_sensitive (false);
1191  _region_actions->get_action("quantize-region")->set_sensitive (false);
1192  _region_actions->get_action("legatize-region")->set_sensitive (false);
1193  _region_actions->get_action("remove-overlap")->set_sensitive (false);
1194  _region_actions->get_action("fork-region")->set_sensitive (false);
1195  _region_actions->get_action("insert-patch-change-context")->set_sensitive (false);
1196  _region_actions->get_action("insert-patch-change")->set_sensitive (false);
1197  _region_actions->get_action("transpose-region")->set_sensitive (false);
1198  } else {
1199  editor_menu_actions->get_action("RegionMenuMIDI")->set_sensitive (true);
1200  /* others were already marked sensitive */
1201  }
1202 
1203  if (_edit_point == EditAtMouse) {
1204  _region_actions->get_action("set-region-sync-position")->set_sensitive (false);
1205  _region_actions->get_action("trim-front")->set_sensitive (false);
1206  _region_actions->get_action("trim-back")->set_sensitive (false);
1207  _region_actions->get_action("split-region")->set_sensitive (false);
1208  _region_actions->get_action("place-transient")->set_sensitive (false);
1209  }
1210 
1211  if (have_compound_regions) {
1212  _region_actions->get_action("uncombine-regions")->set_sensitive (true);
1213  } else {
1214  _region_actions->get_action("uncombine-regions")->set_sensitive (false);
1215  }
1216 
1217  if (have_audio) {
1218 
1219  if (have_envelope_active && !have_envelope_inactive) {
1220  Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_active ();
1221  } else if (have_envelope_active && have_envelope_inactive) {
1222  // Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-gain-envelope-active"))->set_inconsistent ();
1223  }
1224 
1225  } else {
1226 
1227  _region_actions->get_action("analyze-region")->set_sensitive (false);
1228  _region_actions->get_action("reset-region-gain-envelopes")->set_sensitive (false);
1229  _region_actions->get_action("toggle-region-gain-envelope-active")->set_sensitive (false);
1230  _region_actions->get_action("pitch-shift-region")->set_sensitive (false);
1231 
1232  }
1233 
1234  if (!have_non_unity_scale_amplitude || !have_audio) {
1235  _region_actions->get_action("reset-region-scale-amplitude")->set_sensitive (false);
1236  }
1237 
1238  Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock"));
1239  a->set_active (have_locked && !have_unlocked);
1240  if (have_locked && have_unlocked) {
1241  // a->set_inconsistent ();
1242  }
1243 
1244  a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-video-lock"));
1245  a->set_active (have_video_locked && !have_video_unlocked);
1246  if (have_video_locked && have_video_unlocked) {
1247  // a->set_inconsistent ();
1248  }
1249 
1250  a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
1251  a->set_active (have_position_lock_style_music && !have_position_lock_style_audio);
1252 
1253  if (have_position_lock_style_music && have_position_lock_style_audio) {
1254  // a->set_inconsistent ();
1255  }
1256 
1257  a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-mute"));
1258  a->set_active (have_muted && !have_unmuted);
1259  if (have_muted && have_unmuted) {
1260  // a->set_inconsistent ();
1261  }
1262 
1263  a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-opaque-region"));
1264  a->set_active (have_opaque && !have_non_opaque);
1265  if (have_opaque && have_non_opaque) {
1266  // a->set_inconsistent ();
1267  }
1268 
1269  if (!have_not_at_natural_position) {
1270  _region_actions->get_action("naturalize-region")->set_sensitive (false);
1271  }
1272 
1273  /* XXX: should also check that there is a track of the appropriate type for the selected region */
1274  if (_edit_point == EditAtMouse || _regions->get_single_selection() == 0 || selection->tracks.empty()) {
1275  _region_actions->get_action("insert-region-from-region-list")->set_sensitive (false);
1276  } else {
1277  _region_actions->get_action("insert-region-from-region-list")->set_sensitive (true);
1278  }
1279 
1280  a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-in"));
1281  a->set_active (have_active_fade_in && !have_inactive_fade_in);
1282  if (have_active_fade_in && have_inactive_fade_in) {
1283  // a->set_inconsistent ();
1284  }
1285 
1286  a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fade-out"));
1287  a->set_active (have_active_fade_out && !have_inactive_fade_out);
1288 
1289  if (have_active_fade_out && have_inactive_fade_out) {
1290  // a->set_inconsistent ();
1291  }
1292 
1293  bool const have_active_fade = have_active_fade_in || have_active_fade_out;
1294  bool const have_inactive_fade = have_inactive_fade_in || have_inactive_fade_out;
1295 
1296  a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-fades"));
1297  a->set_active (have_active_fade && !have_inactive_fade);
1298 
1299  if (have_active_fade && have_inactive_fade) {
1300  // a->set_inconsistent ();
1301  }
1302 
1303  _ignore_region_action = false;
1304 
1305  _all_region_actions_sensitized = false;
1306 }
1307 
1308 
1309 void
1311 {
1312  _regions->block_change_connection (true);
1313  editor_regions_selection_changed_connection.block(true);
1314 
1315  if (_region_selection_change_updates_region_list) {
1316  _regions->unselect_all ();
1317  }
1318 
1319  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1320  (*i)->set_selected_regionviews (selection->regions);
1321  }
1322 
1323  if (_region_selection_change_updates_region_list) {
1324  _regions->set_selected (selection->regions);
1325  }
1326 
1327  _regions->block_change_connection (false);
1328  editor_regions_selection_changed_connection.block(false);
1329 
1330  if (!_all_region_actions_sensitized) {
1331  /* This selection change might have changed what region actions
1332  are allowed, so sensitize them all in case a key is pressed.
1333  */
1334  sensitize_all_region_actions (true);
1335  }
1336 
1337  if (_session && !_session->transport_rolling() && !selection->regions.empty()) {
1338  maybe_locate_with_edit_preroll (selection->regions.start());
1339  }
1340 }
1341 
1342 void
1344 {
1345  for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1346  (*i)->set_selected_points (selection->points);
1347  }
1348 }
1349 
1350 void
1352 {
1353  list<Selectable *> touched;
1354 
1355  if (!clicked_routeview) {
1356  return;
1357  }
1358 
1359  begin_reversible_selection_op (X_("Select All in Track"));
1360 
1361  clicked_routeview->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1362 
1363  switch (op) {
1364  case Selection::Toggle:
1365  selection->add (touched);
1366  break;
1367  case Selection::Set:
1368  selection->set (touched);
1369  break;
1370  case Selection::Extend:
1371  /* meaningless, because we're selecting everything */
1372  break;
1373  case Selection::Add:
1374  selection->add (touched);
1375  break;
1376  }
1377 
1378  commit_reversible_selection_op ();
1379 }
1380 
1381 bool
1383 {
1384  bool selected = false;
1385 
1386  for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1387  MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1388  if (mrv) {
1389  mrv->select_all_notes ();
1390  selected = true;
1391  }
1392  }
1393 
1394  MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(entered_regionview);
1395  if (mrv) {
1396  mrv->select_all_notes ();
1397  selected = true;
1398  }
1399 
1400  return selected;
1401 }
1402 
1403 void
1405 {
1406  list<Selectable *> touched;
1407 
1408  TrackViewList ts = track_views;
1409 
1410  if (internal_editing() && select_all_internal_edit(op)) {
1411  return; // Selected notes
1412  }
1413 
1414  for (TrackViewList::iterator iter = ts.begin(); iter != ts.end(); ++iter) {
1415  if ((*iter)->hidden()) {
1416  continue;
1417  }
1418  (*iter)->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
1419  selection->add (*iter);
1420  }
1421 
1422 
1423  begin_reversible_selection_op (X_("select all"));
1424  switch (op) {
1425  case Selection::Add:
1426  selection->add (touched);
1427  break;
1428  case Selection::Toggle:
1429  selection->add (touched);
1430  break;
1431  case Selection::Set:
1432  selection->set (touched);
1433  break;
1434  case Selection::Extend:
1435  /* meaningless, because we're selecting everything */
1436  break;
1437  }
1438  commit_reversible_selection_op ();
1439 }
1440 
1441 void
1443 {
1444  list<Selectable *> touched;
1445 
1446  if (!clicked_routeview) {
1447  return;
1448  }
1449 
1450  begin_reversible_selection_op (X_("Invert Selection in Track"));
1451  clicked_routeview->get_inverted_selectables (*selection, touched);
1452  selection->set (touched);
1453  commit_reversible_selection_op ();
1454 }
1455 
1456 void
1458 {
1459  list<Selectable *> touched;
1460 
1461  if (internal_editing()) {
1462  for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1463  MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1464  if (mrv) {
1465  mrv->invert_selection ();
1466  }
1467  }
1468  return;
1469  }
1470 
1471  for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1472  if ((*iter)->hidden()) {
1473  continue;
1474  }
1475  (*iter)->get_inverted_selectables (*selection, touched);
1476  }
1477 
1478  begin_reversible_selection_op (X_("Invert Selection"));
1479  selection->set (touched);
1480  commit_reversible_selection_op ();
1481 }
1482 
1490 void
1491 Editor::select_all_within (framepos_t start, framepos_t end, double top, double bot, const TrackViewList& tracklist, Selection::Operation op, bool preserve_if_selected)
1492 {
1493  list<Selectable*> found;
1494 
1495  for (TrackViewList::const_iterator iter = tracklist.begin(); iter != tracklist.end(); ++iter) {
1496 
1497  if ((*iter)->hidden()) {
1498  continue;
1499  }
1500 
1501  (*iter)->get_selectables (start, end, top, bot, found);
1502  }
1503 
1504  if (found.empty()) {
1505  selection->clear_objects();
1506  selection->clear_time ();
1507  return;
1508  }
1509 
1510  if (preserve_if_selected && op != Selection::Toggle) {
1511  list<Selectable*>::iterator i = found.begin();
1512  while (i != found.end() && (*i)->get_selected()) {
1513  ++i;
1514  }
1515 
1516  if (i == found.end()) {
1517  return;
1518  }
1519  }
1520 
1521  begin_reversible_selection_op (X_("select all within"));
1522  switch (op) {
1523  case Selection::Add:
1524  selection->add (found);
1525  break;
1526  case Selection::Toggle:
1527  selection->toggle (found);
1528  break;
1529  case Selection::Set:
1530  selection->set (found);
1531  break;
1532  case Selection::Extend:
1533  /* not defined yet */
1534  break;
1535  }
1536 
1537  commit_reversible_selection_op ();
1538 }
1539 
1540 void
1542 {
1543  if (selection->regions.empty()) {
1544  return;
1545  }
1546 
1547  /* find all the tracks that have selected regions */
1548 
1549  set<TimeAxisView*> tracks;
1550 
1551  for (RegionSelection::const_iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
1552  tracks.insert (&(*r)->get_time_axis_view());
1553  }
1554 
1555  TrackViewList tvl;
1556  tvl.insert (tvl.end(), tracks.begin(), tracks.end());
1557 
1558  /* select range (this will clear the region selection) */
1559 
1560  selection->set (selection->regions.start(), selection->regions.end_frame());
1561 
1562  /* and select the tracks */
1563 
1564  selection->set (tvl);
1565 
1566  if (!Profile->get_sae()) {
1567  set_mouse_mode (Editing::MouseRange, false);
1568  }
1569 }
1570 
1571 void
1573 {
1574  Location* location;
1575 
1576  if ((location = _session->locations()->auto_punch_location()) == 0) {
1577  return;
1578  }
1579 
1580  set_selection_from_range (*location);
1581 }
1582 
1583 void
1585 {
1586  Location* location;
1587 
1588  if ((location = _session->locations()->auto_loop_location()) == 0) {
1589  return;
1590  }
1591  set_selection_from_range (*location);
1592 }
1593 
1594 void
1596 {
1597  begin_reversible_selection_op (X_("set selection from range"));
1598  selection->set (loc.start(), loc.end());
1599  commit_reversible_selection_op ();
1600 
1601  if (!Profile->get_sae()) {
1602  set_mouse_mode (Editing::MouseRange, false);
1603  }
1604 }
1605 
1606 void
1608 {
1609  list<Selectable *> touched;
1610 
1611  if (selection->time.empty()) {
1612  return;
1613  }
1614 
1615  framepos_t start = selection->time[clicked_selection].start;
1616  framepos_t end = selection->time[clicked_selection].end;
1617 
1618  if (end - start < 1) {
1619  return;
1620  }
1621 
1622  TrackViewList* ts;
1623 
1624  if (selection->tracks.empty()) {
1625  ts = &track_views;
1626  } else {
1627  ts = &selection->tracks;
1628  }
1629 
1630  for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1631  if ((*iter)->hidden()) {
1632  continue;
1633  }
1634  (*iter)->get_selectables (start, end - 1, 0, DBL_MAX, touched);
1635  }
1636 
1637  begin_reversible_selection_op (X_("select all from range"));
1638  selection->set (touched);
1639  commit_reversible_selection_op ();
1640 }
1641 
1642 
1643 void
1645 {
1646  Location* location = _session->locations()->auto_punch_location();
1647  list<Selectable *> touched;
1648 
1649  if (location == 0 || (location->end() - location->start() <= 1)) {
1650  return;
1651  }
1652 
1653 
1654  TrackViewList* ts;
1655 
1656  if (selection->tracks.empty()) {
1657  ts = &track_views;
1658  } else {
1659  ts = &selection->tracks;
1660  }
1661 
1662  for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1663  if ((*iter)->hidden()) {
1664  continue;
1665  }
1666  (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1667  }
1668  begin_reversible_selection_op (X_("select all from punch"));
1669  selection->set (touched);
1670  commit_reversible_selection_op ();
1671 
1672 }
1673 
1674 void
1676 {
1677  Location* location = _session->locations()->auto_loop_location();
1678  list<Selectable *> touched;
1679 
1680  if (location == 0 || (location->end() - location->start() <= 1)) {
1681  return;
1682  }
1683 
1684 
1685  TrackViewList* ts;
1686 
1687  if (selection->tracks.empty()) {
1688  ts = &track_views;
1689  } else {
1690  ts = &selection->tracks;
1691  }
1692 
1693  for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1694  if ((*iter)->hidden()) {
1695  continue;
1696  }
1697  (*iter)->get_selectables (location->start(), location->end() - 1, 0, DBL_MAX, touched);
1698  }
1699  begin_reversible_selection_op (X_("select all from loop"));
1700  selection->set (touched);
1701  commit_reversible_selection_op ();
1702 
1703 }
1704 
1705 void
1707 {
1708  framepos_t start;
1709  framepos_t end;
1710  list<Selectable *> touched;
1711 
1712  if (after) {
1713  start = cursor->current_frame();
1714  end = _session->current_end_frame();
1715  } else {
1716  if (cursor->current_frame() > 0) {
1717  start = 0;
1718  end = cursor->current_frame() - 1;
1719  } else {
1720  return;
1721  }
1722  }
1723 
1724  if (internal_editing()) {
1725  for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1726  MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1727  if (mrv) {
1728  mrv->select_range (start, end);
1729  }
1730  }
1731  return;
1732  }
1733 
1734  if (after) {
1735  begin_reversible_selection_op (X_("select all after cursor"));
1736  } else {
1737  begin_reversible_selection_op (X_("select all before cursor"));
1738  }
1739 
1740  TrackViewList* ts;
1741 
1742  if (selection->tracks.empty()) {
1743  ts = &track_views;
1744  } else {
1745  ts = &selection->tracks;
1746  }
1747 
1748  for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1749  if ((*iter)->hidden()) {
1750  continue;
1751  }
1752  (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1753  }
1754  selection->set (touched);
1755  commit_reversible_selection_op ();
1756 }
1757 
1758 void
1760 {
1761  framepos_t start;
1762  framepos_t end;
1763  list<Selectable *> touched;
1764 
1765  if (after) {
1766  start = get_preferred_edit_position(EDIT_IGNORE_NONE, true);
1767  end = _session->current_end_frame();
1768  } else {
1769  if ((end = get_preferred_edit_position(EDIT_IGNORE_NONE, true)) > 1) {
1770  start = 0;
1771  end -= 1;
1772  } else {
1773  return;
1774  }
1775  }
1776 
1777  if (internal_editing()) {
1778  for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1779  MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1780  mrv->select_range (start, end);
1781  }
1782  return;
1783  }
1784 
1785  if (after) {
1786  begin_reversible_selection_op (X_("select all after edit"));
1787  } else {
1788  begin_reversible_selection_op (X_("select all before edit"));
1789  }
1790 
1791  TrackViewList* ts;
1792 
1793  if (selection->tracks.empty()) {
1794  ts = &track_views;
1795  } else {
1796  ts = &selection->tracks;
1797  }
1798 
1799  for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1800  if ((*iter)->hidden()) {
1801  continue;
1802  }
1803  (*iter)->get_selectables (start, end, 0, DBL_MAX, touched);
1804  }
1805  selection->set (touched);
1806  commit_reversible_selection_op ();
1807 }
1808 
1809 void
1811 {
1812  framepos_t start;
1813  framepos_t end;
1814  list<Selectable *> touched;
1815 
1816  if (!get_edit_op_range (start, end)) {
1817  return;
1818  }
1819 
1820  if (internal_editing()) {
1821  for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
1822  MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
1823  mrv->select_range (start, end);
1824  }
1825  return;
1826  }
1827 
1828  TrackViewList* ts;
1829 
1830  if (selection->tracks.empty()) {
1831  ts = &track_views;
1832  } else {
1833  ts = &selection->tracks;
1834  }
1835 
1836  for (TrackViewList::iterator iter = ts->begin(); iter != ts->end(); ++iter) {
1837  if ((*iter)->hidden()) {
1838  continue;
1839  }
1840  (*iter)->get_selectables (start, end, 0, DBL_MAX, touched, within);
1841  }
1842 
1843  begin_reversible_selection_op (X_("Select all Selectables Between"));
1844  selection->set (touched);
1845  commit_reversible_selection_op ();
1846 }
1847 
1848 void
1850 {
1851  framepos_t start;
1852  framepos_t end;
1853 
1854  if ( !selection->time.empty() ) {
1855  selection->clear_time ();
1856  }
1857 
1858  if (!get_edit_op_range (start, end)) {
1859  return;
1860  }
1861 
1862  begin_reversible_selection_op (X_("Select Range Between"));
1863  set_mouse_mode (MouseRange);
1864  selection->set (start, end);
1865  commit_reversible_selection_op ();
1866 }
1867 
1868 bool
1870 {
1871 // framepos_t m;
1872 // bool ignored;
1873 
1874  /* if an explicit range exists, use it */
1875 
1876  if ( (mouse_mode == MouseRange || get_smart_mode() ) && !selection->time.empty()) {
1877  /* we know that these are ordered */
1878  start = selection->time.start();
1879  end = selection->time.end_frame();
1880  return true;
1881  } else {
1882  start = 0;
1883  end = 0;
1884  return false;
1885  }
1886 
1887 // if (!mouse_frame (m, ignored)) {
1888 // /* mouse is not in a canvas, try playhead+selected marker.
1889 // this is probably most true when using menus.
1890 // */
1891 //
1892 // if (selection->markers.empty()) {
1893 // return false;
1894 // }
1895 
1896 // start = selection->markers.front()->position();
1897 // end = _session->audible_frame();
1898 
1899 // } else {
1900 
1901 // switch (_edit_point) {
1902 // case EditAtPlayhead:
1903 // if (selection->markers.empty()) {
1904 // /* use mouse + playhead */
1905 // start = m;
1906 // end = _session->audible_frame();
1907 // } else {
1908 // /* use playhead + selected marker */
1909 // start = _session->audible_frame();
1910 // end = selection->markers.front()->position();
1911 // }
1912 // break;
1913 
1914 // case EditAtMouse:
1915 // /* use mouse + selected marker */
1916 // if (selection->markers.empty()) {
1917 // start = m;
1918 // end = _session->audible_frame();
1919 // } else {
1920 // start = selection->markers.front()->position();
1921 // end = m;
1922 // }
1923 // break;
1924 
1925 // case EditAtSelectedMarker:
1926 // /* use mouse + selected marker */
1927 // if (selection->markers.empty()) {
1928 
1929 // MessageDialog win (_("No edit range defined"),
1930 // false,
1931 // MESSAGE_INFO,
1932 // BUTTONS_OK);
1933 
1934 // win.set_secondary_text (
1935 // _("the edit point is Selected Marker\nbut there is no selected marker."));
1936 
1937 
1938 // win.set_default_response (RESPONSE_CLOSE);
1939 // win.set_position (Gtk::WIN_POS_MOUSE);
1940 // win.show_all();
1941 
1942 // win.run ();
1943 
1944 // return false; // NO RANGE
1945 // }
1946 // start = selection->markers.front()->position();
1947 // end = m;
1948 // break;
1949 // }
1950 // }
1951 
1952 // if (start == end) {
1953 // return false;
1954 // }
1955 
1956 // if (start > end) {
1957 // swap (start, end);
1958 // }
1959 
1960  /* turn range into one delimited by start...end,
1961  not start...end-1
1962  */
1963 
1964 // end++;
1965 
1966 // return true;
1967 }
1968 
1969 void
1971 {
1972  begin_reversible_selection_op (X_("Deselect All"));
1973  selection->clear ();
1974  commit_reversible_selection_op ();
1975 }
1976 
1977 long
1979 {
1980  begin_reversible_selection_op (X_("Select Range"));
1981  selection->add (clicked_axisview);
1982  selection->time.clear ();
1983  long ret = selection->set (s, e);
1984  commit_reversible_selection_op ();
1985  return ret;
1986 }
RegionView * find_view(boost::shared_ptr< const ARDOUR::Region >)
Definition: streamview.cc:481
bool add(RegionView *)
std::vector< Glib::RefPtr< Gtk::Action > > track_selection_sensitive_actions
Definition: actions.cc:53
void set_selected_track_as_side_effect(Selection::Operation op)
TimeAxisView & get_time_axis_view() const
bool select_all_internal_edit(Selection::Operation)
bool get_sae() const
Definition: profile.h:48
Definition: ardour_ui.h:130
shared_ptr< T > dynamic_pointer_cast(shared_ptr< U > const &r)
Definition: shared_ptr.hpp:396
std::vector< Glib::RefPtr< Gtk::Action > > time_selection_sensitive_actions
Definition: actions.cc:55
std::vector< boost::shared_ptr< TimeAxisView > > Children
virtual TrackViewList add(TrackViewList const &)
void track_selection_changed()
void get_region_list_equivalent_regions(boost::shared_ptr< Region >, std::vector< boost::shared_ptr< Region > > &)
Definition: playlist.cc:849
bool extend_selection_to_track(TimeAxisView &)
void set_selected_track(TimeAxisView &, Selection::Operation op=Selection::Set, bool no_remove=false)
bool set_selected_regionview_from_map_event(GdkEventAny *, StreamView *, boost::weak_ptr< ARDOUR::Region >)
framepos_t end() const
Definition: location.h:72
Definition: Beats.hpp:239
bool whole_file() const
Definition: region.h:169
StreamView * view() const
void select_all_selectables_using_edit(bool)
void select_range_between()
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
Definition: region.cc:63
double y_position() const
bool fade_in_active() const
Definition: audioregion.h:84
void set_selected_track_from_click(bool press, Selection::Operation op=Selection::Set, bool no_remove=false)
void invert_selection()
void select_all_selectables_using_loop()
LIBGTKMM2EXT_API void set_sensitive(std::vector< Glib::RefPtr< Gtk::Action > > &actions, bool)
GQuark PropertyID
void sensitize_all_region_actions(bool)
void set_selected_regionview_from_region_list(boost::shared_ptr< ARDOUR::Region > region, Selection::Operation op=Selection::Set)
void select_range(framepos_t start, framepos_t end)
framepos_t current_frame() const
#define X_(Text)
Definition: i18n.h:13
bool get_edit_op_range(framepos_t &start, framepos_t &end) const
uint32_t order_key() const
Definition: route.cc:306
void point_selection_changed()
bool video_locked() const
Definition: region.h:166
boost::shared_ptr< ARDOUR::Region > region() const
Definition: region_view.h:66
void set_selection_from_loop()
bool fade_out_active() const
Definition: audioregion.h:85
Definition: amp.h:29
void set_selection_from_punch()
void set_selection_from_range(ARDOUR::Location &)
gain_t scale_amplitude() const
Definition: audioregion.h:78
bool muted() const
Definition: region.h:162
bool is_active() const
Definition: route_group.h:66
bool is_compound() const
Definition: region.cc:1694
boost::shared_ptr< ARDOUR::Track > track() const
Definition: route_ui.cc:1738
bool enabled_property(PBD::PropertyID)
Definition: route_group.cc:516
void get_equivalent_regions(RegionView *rv, std::vector< RegionView * > &, PBD::PropertyID) const
void select_all_tracks()
void select_all_objects(Selection::Operation op)
boost::shared_ptr< Playlist > playlist()
Definition: track.cc:590
void swap(shared_ptr< T > &a, shared_ptr< T > &b)
Definition: shared_ptr.hpp:381
void select_all_selectables_between(bool within)
void mapover_tracks(sigc::slot< void, RouteTimeAxisView &, uint32_t > sl, TimeAxisView *, PBD::PropertyID) const
void mapover_tracks_with_unique_playlists(sigc::slot< void, RouteTimeAxisView &, uint32_t > sl, TimeAxisView *, PBD::PropertyID) const
int64_t framepos_t
Definition: types.h:66
void get_onscreen_tracks(TrackViewList &)
void deselect_all()
LIBARDOUR_API PBD::PropertyDescriptor< bool > regions
Definition: playlist.cc:51
void select_all_in_track(Selection::Operation op)
PositionLockStyle position_lock_style() const
Definition: region.h:178
LIBARDOUR_API PBD::PropertyDescriptor< bool > active
Definition: route_group.cc:43
LIBARDOUR_API RuntimeProfile * Profile
Definition: globals.cc:120
void mapped_get_equivalent_regions(RouteTimeAxisView &, uint32_t, RegionView *, std::vector< RegionView * > *) const
void get_equivalent_regions(boost::shared_ptr< Region >, std::vector< boost::shared_ptr< Region > > &)
Definition: playlist.cc:831
void time_selection_changed()
void select_all_selectables_using_punch()
bool locked() const
Definition: region.h:164
uint32_t n_channels() const
Definition: region.h:259
RouteGroup * route_group() const
LIBARDOUR_API PBD::PropertyDescriptor< bool > select
Definition: route_group.cc:48
Definition: debug.h:30
bool set_selected_regionview_from_click(bool press, Selection::Operation op=Selection::Set)
bool set_selected_control_point_from_click(bool press, Selection::Operation op=Selection::Set)
int get_regionview_count_from_region_list(boost::shared_ptr< ARDOUR::Region >)
bool opaque() const
Definition: region.h:163
framepos_t start() const
Definition: location.h:71
static const framepos_t max_framepos
Definition: types.h:78
void region_selection_changed()
void invert_selection_in_track()
void sensitize_the_right_region_actions()
long select_range(framepos_t, framepos_t)
void set_selection_from_region()
void select_all_selectables_using_time_selection()
void select_all_selectables_using_cursor(EditorCursor *, bool)
bool at_natural_position() const
Definition: region.cc:496
boost::shared_ptr< ARDOUR::Route > route() const
Definition: route_ui.h:76
bool empty() const
Definition: route_group.h:78
void select_all_within(framepos_t, framepos_t, double, double, TrackViewList const &, Selection::Operation, bool)
bool envelope_active() const
Definition: audioregion.h:83