~ubuntu-branches/ubuntu/utopic/ardour3/utopic

« back to all changes in this revision

Viewing changes to gtk2_ardour/editor_selection.cc

  • Committer: Package Import Robot
  • Author(s): Felipe Sateler
  • Date: 2013-09-21 19:05:02 UTC
  • Revision ID: package-import@ubuntu.com-20130921190502-8gsftrku6jnzhd7v
Tags: upstream-3.4~dfsg
ImportĀ upstreamĀ versionĀ 3.4~dfsg

Show diffs side-by-side

added added

removed removed

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