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

« back to all changes in this revision

Viewing changes to gtk2_ardour/automation_streamview.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) 2001-2007 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
#include <cmath>
 
20
#include <cassert>
 
21
#include <utility>
 
22
 
 
23
#include <gtkmm.h>
 
24
 
 
25
#include <gtkmm2ext/gtk_ui.h>
 
26
 
 
27
#include "ardour/midi_region.h"
 
28
#include "ardour/midi_source.h"
 
29
 
 
30
#include "automation_streamview.h"
 
31
#include "region_view.h"
 
32
#include "automation_region_view.h"
 
33
#include "automation_time_axis.h"
 
34
#include "canvas-simplerect.h"
 
35
#include "region_selection.h"
 
36
#include "selection.h"
 
37
#include "public_editor.h"
 
38
#include "ardour_ui.h"
 
39
#include "rgb_macros.h"
 
40
#include "gui_thread.h"
 
41
#include "utils.h"
 
42
#include "simplerect.h"
 
43
#include "simpleline.h"
 
44
 
 
45
using namespace std;
 
46
using namespace ARDOUR;
 
47
using namespace PBD;
 
48
using namespace Editing;
 
49
 
 
50
AutomationStreamView::AutomationStreamView (AutomationTimeAxisView& tv)
 
51
        : StreamView (*dynamic_cast<RouteTimeAxisView*>(tv.get_parent()),
 
52
                      new ArdourCanvas::Group(*tv.canvas_background()),
 
53
                      new ArdourCanvas::Group(*tv.canvas_display()))
 
54
        , _automation_view(tv)
 
55
        , _pending_automation_state (Off)
 
56
{
 
57
        //canvas_rect->property_fill_color_rgba() = stream_base_color;
 
58
        canvas_rect->property_outline_color_rgba() = RGBA_BLACK;
 
59
}
 
60
 
 
61
AutomationStreamView::~AutomationStreamView ()
 
62
{
 
63
}
 
64
 
 
65
 
 
66
RegionView*
 
67
AutomationStreamView::add_region_view_internal (boost::shared_ptr<Region> region, bool wfd, bool /*recording*/)
 
68
{
 
69
        assert (region);
 
70
 
 
71
        if (wfd) {
 
72
                boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(region);
 
73
                if (mr) {
 
74
                        mr->midi_source()->load_model();
 
75
                }
 
76
        }
 
77
 
 
78
        const boost::shared_ptr<AutomationControl> control = boost::dynamic_pointer_cast<AutomationControl> (
 
79
                region->control (_automation_view.parameter(), true)
 
80
                );
 
81
 
 
82
        boost::shared_ptr<AutomationList> list;
 
83
        if (control) {
 
84
                list = boost::dynamic_pointer_cast<AutomationList>(control->list());
 
85
                assert(!control->list() || list);
 
86
        }
 
87
 
 
88
        AutomationRegionView *region_view;
 
89
        std::list<RegionView *>::iterator i;
 
90
 
 
91
        for (i = region_views.begin(); i != region_views.end(); ++i) {
 
92
                if ((*i)->region() == region) {
 
93
 
 
94
                        /* great. we already have an AutomationRegionView for this Region. use it again. */
 
95
                        AutomationRegionView* arv = dynamic_cast<AutomationRegionView*>(*i);;
 
96
 
 
97
                        if (arv->line()) {
 
98
                                arv->line()->set_list (list);
 
99
                        }
 
100
                        (*i)->set_valid (true);
 
101
                        (*i)->enable_display(wfd);
 
102
                        display_region(arv);
 
103
 
 
104
                        return 0;
 
105
                }
 
106
        }
 
107
 
 
108
        region_view = new AutomationRegionView (
 
109
                _canvas_group, _automation_view, region,
 
110
                _automation_view.parameter (), list,
 
111
                _samples_per_unit, region_color
 
112
                );
 
113
 
 
114
        region_view->init (region_color, false);
 
115
        region_views.push_front (region_view);
 
116
 
 
117
        /* follow global waveform setting */
 
118
 
 
119
        if (wfd) {
 
120
                region_view->enable_display(true);
 
121
                //region_view->midi_region()->midi_source(0)->load_model();
 
122
        }
 
123
 
 
124
        display_region(region_view);
 
125
 
 
126
        /* catch regionview going away */
 
127
        region->DropReferences.connect (*this, invalidator (*this), boost::bind (&AutomationStreamView::remove_region_view, this, boost::weak_ptr<Region>(region)), gui_context());
 
128
 
 
129
        /* setup automation state for this region */
 
130
        boost::shared_ptr<AutomationLine> line = region_view->line ();
 
131
        if (line && line->the_list()) {
 
132
                line->the_list()->set_automation_state (automation_state ());
 
133
        }
 
134
 
 
135
        RegionViewAdded (region_view);
 
136
 
 
137
        return region_view;
 
138
}
 
139
 
 
140
void
 
141
AutomationStreamView::display_region(AutomationRegionView* region_view)
 
142
{
 
143
        region_view->line().reset();
 
144
}
 
145
 
 
146
void
 
147
AutomationStreamView::set_automation_state (AutoState state)
 
148
{
 
149
        /* Setting the automation state for this view sets the state of all regions' lists to the same thing */
 
150
 
 
151
        if (region_views.empty()) {
 
152
                _pending_automation_state = state;
 
153
        } else {
 
154
                list<boost::shared_ptr<AutomationLine> > lines = get_lines ();
 
155
 
 
156
                for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
 
157
                        if ((*i)->the_list()) {
 
158
                                (*i)->the_list()->set_automation_state (state);
 
159
                        }
 
160
                }
 
161
        }
 
162
}
 
163
 
 
164
void
 
165
AutomationStreamView::redisplay_track ()
 
166
{
 
167
        // Flag region views as invalid and disable drawing
 
168
        for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
 
169
                (*i)->set_valid (false);
 
170
                (*i)->enable_display(false);
 
171
        }
 
172
 
 
173
        // Add and display region views, and flag them as valid
 
174
        if (_trackview.is_track()) {
 
175
                _trackview.track()->playlist()->foreach_region (
 
176
                        sigc::hide_return (sigc::mem_fun (*this, &StreamView::add_region_view))
 
177
                        );
 
178
        }
 
179
 
 
180
        // Stack regions by layer, and remove invalid regions
 
181
        layer_regions();
 
182
}
 
183
 
 
184
 
 
185
void
 
186
AutomationStreamView::setup_rec_box ()
 
187
{
 
188
}
 
189
 
 
190
void
 
191
AutomationStreamView::color_handler ()
 
192
{
 
193
        /*if (_trackview.is_midi_track()) {
 
194
                canvas_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiTrackBase.get();
 
195
        }
 
196
 
 
197
        if (!_trackview.is_midi_track()) {
 
198
                canvas_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiBusBase.get();;
 
199
        }*/
 
200
}
 
201
 
 
202
AutoState
 
203
AutomationStreamView::automation_state () const
 
204
{
 
205
        if (region_views.empty()) {
 
206
                return _pending_automation_state;
 
207
        }
 
208
 
 
209
        boost::shared_ptr<AutomationLine> line = ((AutomationRegionView*) region_views.front())->line ();
 
210
        if (!line || !line->the_list()) {
 
211
                return Off;
 
212
        }
 
213
 
 
214
        return line->the_list()->automation_state ();
 
215
}
 
216
 
 
217
bool
 
218
AutomationStreamView::has_automation () const
 
219
{
 
220
        list<boost::shared_ptr<AutomationLine> > lines = get_lines ();
 
221
 
 
222
        for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
 
223
                if ((*i)->npoints() > 0) {
 
224
                        return true;
 
225
                }
 
226
        }
 
227
 
 
228
        return false;
 
229
}
 
230
 
 
231
/** Our parent AutomationTimeAxisView calls this when the user requests a particular
 
232
 *  InterpolationStyle; tell the AutomationLists in our regions.
 
233
 */
 
234
void
 
235
AutomationStreamView::set_interpolation (AutomationList::InterpolationStyle s)
 
236
{
 
237
        list<boost::shared_ptr<AutomationLine> > lines = get_lines ();
 
238
 
 
239
        for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
 
240
                (*i)->the_list()->set_interpolation (s);
 
241
        }
 
242
}
 
243
 
 
244
AutomationList::InterpolationStyle
 
245
AutomationStreamView::interpolation () const
 
246
{
 
247
        if (region_views.empty()) {
 
248
                return AutomationList::Linear;
 
249
        }
 
250
 
 
251
        AutomationRegionView* v = dynamic_cast<AutomationRegionView*> (region_views.front());
 
252
        if (v) {
 
253
                return v->line()->the_list()->interpolation ();
 
254
        }
 
255
        return AutomationList::Linear;
 
256
}
 
257
 
 
258
/** Clear all automation displayed in this view */
 
259
void
 
260
AutomationStreamView::clear ()
 
261
{
 
262
        list<boost::shared_ptr<AutomationLine> > lines = get_lines ();
 
263
 
 
264
        for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
 
265
                (*i)->clear ();
 
266
        }
 
267
}
 
268
 
 
269
/** @param start Start position in session frames.
 
270
 *  @param end End position in session frames.
 
271
 *  @param bot Bottom position expressed as a fraction of track height where 0 is the bottom of the track.
 
272
 *  @param top Top position expressed as a fraction of track height where 0 is the bottom of the track.
 
273
 *  NOTE: this y system is different to that for the StreamView method that this overrides, which is a little
 
274
 *  confusing.
 
275
 */
 
276
void
 
277
AutomationStreamView::get_selectables (framepos_t start, framepos_t end, double botfrac, double topfrac, list<Selectable*>& results)
 
278
{
 
279
        for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
 
280
                AutomationRegionView* arv = dynamic_cast<AutomationRegionView*> (*i);
 
281
                assert (arv);
 
282
                arv->line()->get_selectables (start, end, botfrac, topfrac, results);
 
283
        }
 
284
}
 
285
 
 
286
void
 
287
AutomationStreamView::set_selected_points (PointSelection& ps)
 
288
{
 
289
        list<boost::shared_ptr<AutomationLine> > lines = get_lines ();
 
290
 
 
291
        for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
 
292
                (*i)->set_selected_points (ps);
 
293
        }
 
294
}
 
295
 
 
296
list<boost::shared_ptr<AutomationLine> >
 
297
AutomationStreamView::get_lines () const
 
298
{
 
299
        list<boost::shared_ptr<AutomationLine> > lines;
 
300
 
 
301
        for (list<RegionView*>::const_iterator i = region_views.begin(); i != region_views.end(); ++i) {
 
302
                AutomationRegionView* arv = dynamic_cast<AutomationRegionView*> (*i);
 
303
                assert (arv);
 
304
                lines.push_back (arv->line());
 
305
        }
 
306
 
 
307
        return lines;
 
308
}
 
309
 
 
310
struct RegionPositionSorter {
 
311
        bool operator() (RegionView* a, RegionView* b) {
 
312
                return a->region()->position() < b->region()->position();
 
313
        }
 
314
};
 
315
 
 
316
 
 
317
/** @param pos Position, in session frames.
 
318
 *  @return AutomationLine to paste to for that position, or 0 if there is none appropriate.
 
319
 */
 
320
boost::shared_ptr<AutomationLine>
 
321
AutomationStreamView::paste_line (framepos_t pos)
 
322
{
 
323
        /* XXX: not sure how best to pick this; for now, just use the last region which starts before pos */
 
324
 
 
325
        if (region_views.empty()) {
 
326
                return boost::shared_ptr<AutomationLine> ();
 
327
        }
 
328
 
 
329
        region_views.sort (RegionPositionSorter ());
 
330
 
 
331
        list<RegionView*>::const_iterator prev = region_views.begin ();
 
332
 
 
333
        for (list<RegionView*>::const_iterator i = region_views.begin(); i != region_views.end(); ++i) {
 
334
                if ((*i)->region()->position() > pos) {
 
335
                        break;
 
336
                }
 
337
                prev = i;
 
338
        }
 
339
 
 
340
        boost::shared_ptr<Region> r = (*prev)->region ();
 
341
 
 
342
        /* If *prev doesn't cover pos, it's no good */
 
343
        if (r->position() > pos || ((r->position() + r->length()) < pos)) {
 
344
                return boost::shared_ptr<AutomationLine> ();
 
345
        }
 
346
 
 
347
        AutomationRegionView* arv = dynamic_cast<AutomationRegionView*> (*prev);
 
348
        assert (arv);
 
349
 
 
350
        return arv->line ();
 
351
}