2
Copyright (C) 2001-2007 Paul Davis
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; either version 2 of the License, or
7
(at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
#include <gtkmm2ext/gtk_ui.h>
27
#include "ardour/midi_region.h"
28
#include "ardour/midi_source.h"
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"
42
#include "simplerect.h"
43
#include "simpleline.h"
46
using namespace ARDOUR;
48
using namespace Editing;
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)
57
//canvas_rect->property_fill_color_rgba() = stream_base_color;
58
canvas_rect->property_outline_color_rgba() = RGBA_BLACK;
61
AutomationStreamView::~AutomationStreamView ()
67
AutomationStreamView::add_region_view_internal (boost::shared_ptr<Region> region, bool wfd, bool /*recording*/)
72
boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(region);
74
mr->midi_source()->load_model();
78
const boost::shared_ptr<AutomationControl> control = boost::dynamic_pointer_cast<AutomationControl> (
79
region->control (_automation_view.parameter(), true)
82
boost::shared_ptr<AutomationList> list;
84
list = boost::dynamic_pointer_cast<AutomationList>(control->list());
85
assert(!control->list() || list);
88
AutomationRegionView *region_view;
89
std::list<RegionView *>::iterator i;
91
for (i = region_views.begin(); i != region_views.end(); ++i) {
92
if ((*i)->region() == region) {
94
/* great. we already have an AutomationRegionView for this Region. use it again. */
95
AutomationRegionView* arv = dynamic_cast<AutomationRegionView*>(*i);;
98
arv->line()->set_list (list);
100
(*i)->set_valid (true);
101
(*i)->enable_display(wfd);
108
region_view = new AutomationRegionView (
109
_canvas_group, _automation_view, region,
110
_automation_view.parameter (), list,
111
_samples_per_unit, region_color
114
region_view->init (region_color, false);
115
region_views.push_front (region_view);
117
/* follow global waveform setting */
120
region_view->enable_display(true);
121
//region_view->midi_region()->midi_source(0)->load_model();
124
display_region(region_view);
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());
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 ());
135
RegionViewAdded (region_view);
141
AutomationStreamView::display_region(AutomationRegionView* region_view)
143
region_view->line().reset();
147
AutomationStreamView::set_automation_state (AutoState state)
149
/* Setting the automation state for this view sets the state of all regions' lists to the same thing */
151
if (region_views.empty()) {
152
_pending_automation_state = state;
154
list<boost::shared_ptr<AutomationLine> > lines = get_lines ();
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);
165
AutomationStreamView::redisplay_track ()
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);
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))
180
// Stack regions by layer, and remove invalid regions
186
AutomationStreamView::setup_rec_box ()
191
AutomationStreamView::color_handler ()
193
/*if (_trackview.is_midi_track()) {
194
canvas_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiTrackBase.get();
197
if (!_trackview.is_midi_track()) {
198
canvas_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiBusBase.get();;
203
AutomationStreamView::automation_state () const
205
if (region_views.empty()) {
206
return _pending_automation_state;
209
boost::shared_ptr<AutomationLine> line = ((AutomationRegionView*) region_views.front())->line ();
210
if (!line || !line->the_list()) {
214
return line->the_list()->automation_state ();
218
AutomationStreamView::has_automation () const
220
list<boost::shared_ptr<AutomationLine> > lines = get_lines ();
222
for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
223
if ((*i)->npoints() > 0) {
231
/** Our parent AutomationTimeAxisView calls this when the user requests a particular
232
* InterpolationStyle; tell the AutomationLists in our regions.
235
AutomationStreamView::set_interpolation (AutomationList::InterpolationStyle s)
237
list<boost::shared_ptr<AutomationLine> > lines = get_lines ();
239
for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
240
(*i)->the_list()->set_interpolation (s);
244
AutomationList::InterpolationStyle
245
AutomationStreamView::interpolation () const
247
if (region_views.empty()) {
248
return AutomationList::Linear;
251
AutomationRegionView* v = dynamic_cast<AutomationRegionView*> (region_views.front());
253
return v->line()->the_list()->interpolation ();
255
return AutomationList::Linear;
258
/** Clear all automation displayed in this view */
260
AutomationStreamView::clear ()
262
list<boost::shared_ptr<AutomationLine> > lines = get_lines ();
264
for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
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
277
AutomationStreamView::get_selectables (framepos_t start, framepos_t end, double botfrac, double topfrac, list<Selectable*>& results)
279
for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
280
AutomationRegionView* arv = dynamic_cast<AutomationRegionView*> (*i);
282
arv->line()->get_selectables (start, end, botfrac, topfrac, results);
287
AutomationStreamView::set_selected_points (PointSelection& ps)
289
list<boost::shared_ptr<AutomationLine> > lines = get_lines ();
291
for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
292
(*i)->set_selected_points (ps);
296
list<boost::shared_ptr<AutomationLine> >
297
AutomationStreamView::get_lines () const
299
list<boost::shared_ptr<AutomationLine> > lines;
301
for (list<RegionView*>::const_iterator i = region_views.begin(); i != region_views.end(); ++i) {
302
AutomationRegionView* arv = dynamic_cast<AutomationRegionView*> (*i);
304
lines.push_back (arv->line());
310
struct RegionPositionSorter {
311
bool operator() (RegionView* a, RegionView* b) {
312
return a->region()->position() < b->region()->position();
317
/** @param pos Position, in session frames.
318
* @return AutomationLine to paste to for that position, or 0 if there is none appropriate.
320
boost::shared_ptr<AutomationLine>
321
AutomationStreamView::paste_line (framepos_t pos)
323
/* XXX: not sure how best to pick this; for now, just use the last region which starts before pos */
325
if (region_views.empty()) {
326
return boost::shared_ptr<AutomationLine> ();
329
region_views.sort (RegionPositionSorter ());
331
list<RegionView*>::const_iterator prev = region_views.begin ();
333
for (list<RegionView*>::const_iterator i = region_views.begin(); i != region_views.end(); ++i) {
334
if ((*i)->region()->position() > pos) {
340
boost::shared_ptr<Region> r = (*prev)->region ();
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> ();
347
AutomationRegionView* arv = dynamic_cast<AutomationRegionView*> (*prev);