2 Copyright (C) 2001, 2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <gtkmm2ext/gtk_ui.h>
25 #include <ardour/playlist.h>
26 #include <ardour/region.h>
27 #include <ardour/source.h>
28 #include <ardour/diskstream.h>
29 #include <ardour/track.h>
31 #include "streamview.h"
32 #include "region_view.h"
33 #include "route_time_axis.h"
34 #include "canvas-waveview.h"
35 #include "canvas-simplerect.h"
36 #include "region_selection.h"
37 #include "selection.h"
38 #include "public_editor.h"
39 #include "ardour_ui.h"
40 #include "rgb_macros.h"
41 #include "gui_thread.h"
44 using namespace ARDOUR;
46 using namespace Editing;
48 StreamView::StreamView (RouteTimeAxisView& tv, ArdourCanvas::Group* group)
50 , canvas_group(group ? group : new ArdourCanvas::Group(*_trackview.canvas_display))
51 , canvas_rect(new ArdourCanvas::SimpleRect (*canvas_group))
52 , _samples_per_unit(_trackview.editor.get_current_zoom())
55 , use_rec_regions(tv.editor.show_waveforms_recording())
56 , region_color(_trackview.color())
57 , stream_base_color(0xFFFFFFFF)
60 , layer_display(Overlaid)
61 , last_rec_data_frame(0)
63 /* set_position() will position the group */
65 canvas_rect->property_x1() = 0.0;
66 canvas_rect->property_y1() = 0.0;
67 canvas_rect->property_x2() = _trackview.editor.frame_to_pixel (max_frames);
68 canvas_rect->property_y2() = (double) tv.height;
69 canvas_rect->property_outline_what() = (guint32) (0x2|0x8); // outline RHS and bottom
70 // (Fill/Outline colours set in derived classes)
72 canvas_rect->signal_event().connect (bind (mem_fun (_trackview.editor, &PublicEditor::canvas_stream_view_event), canvas_rect, &_trackview));
74 if (_trackview.is_track()) {
75 _trackview.track()->DiskstreamChanged.connect (mem_fun (*this, &StreamView::diskstream_changed));
76 _trackview.session().TransportStateChange.connect (mem_fun (*this, &StreamView::transport_changed));
77 _trackview.session().TransportLooped.connect (mem_fun (*this, &StreamView::transport_looped));
78 _trackview.get_diskstream()->RecordEnableChanged.connect (mem_fun (*this, &StreamView::rec_enable_changed));
79 _trackview.session().RecordStateChanged.connect (mem_fun (*this, &StreamView::sess_rec_enable_changed));
82 ColorsChanged.connect (mem_fun (*this, &StreamView::color_handler));
85 StreamView::~StreamView ()
87 undisplay_diskstream ();
94 if (_trackview.is_track()) {
95 display_diskstream (_trackview.get_diskstream());
100 StreamView::set_position (gdouble x, gdouble y)
102 canvas_group->property_x() = x;
103 canvas_group->property_y() = y;
108 StreamView::set_height (double h)
110 /* limit the values to something sane-ish */
111 if (h < 10.0 || h > 1000.0) {
115 if (canvas_rect->property_y2() == h) {
120 update_contents_y_position_and_height ();
125 StreamView::set_samples_per_unit (gdouble spp)
127 RegionViewList::iterator i;
133 _samples_per_unit = spp;
135 for (i = region_views.begin(); i != region_views.end(); ++i) {
136 (*i)->set_samples_per_unit (spp);
139 for (vector<RecBoxInfo>::iterator xi = rec_rects.begin(); xi != rec_rects.end(); ++xi) {
140 RecBoxInfo &recbox = (*xi);
142 gdouble xstart = _trackview.editor.frame_to_pixel ( recbox.start );
143 gdouble xend = _trackview.editor.frame_to_pixel ( recbox.start + recbox.length );
145 recbox.rectangle->property_x1() = xstart;
146 recbox.rectangle->property_x2() = xend;
153 StreamView::add_region_view (boost::shared_ptr<Region> r)
155 // ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::add_region_view), r));
157 add_region_view_internal (r, true);
161 StreamView::remove_region_view (boost::weak_ptr<Region> weak_r)
163 ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::remove_region_view), weak_r));
165 boost::shared_ptr<Region> r (weak_r.lock());
171 for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
172 if (((*i)->region()) == r) {
174 region_views.erase (i);
181 StreamView::undisplay_diskstream ()
183 for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
187 region_views.clear();
191 StreamView::display_diskstream (boost::shared_ptr<Diskstream> ds)
193 playlist_change_connection.disconnect();
194 playlist_changed (ds);
195 playlist_change_connection = ds->PlaylistChanged.connect (bind (mem_fun (*this, &StreamView::playlist_changed), ds));
199 StreamView::playlist_modified_weak (boost::weak_ptr<Diskstream> ds)
201 boost::shared_ptr<Diskstream> sp (ds.lock());
206 playlist_modified (sp);
210 StreamView::playlist_modified (boost::shared_ptr<Diskstream> ds)
212 /* we do not allow shared_ptr<T> to be bound to slots */
213 ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::playlist_modified_weak), ds));
215 /* update layers count and the y positions and heights of our regions */
216 if (ds->playlist()) {
217 layers = ds->playlist()->top_layer() + 1;
218 update_contents_y_position_and_height ();
219 redisplay_diskstream ();
224 StreamView::playlist_changed (boost::shared_ptr<Diskstream> ds)
226 /* XXX: binding to a shared_ptr, is this ok? */
227 ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::playlist_changed), ds));
229 /* disconnect from old playlist */
231 for (vector<sigc::connection>::iterator i = playlist_connections.begin(); i != playlist_connections.end(); ++i) {
235 playlist_connections.clear();
236 undisplay_diskstream ();
238 /* update layers count and the y positions and heights of our regions */
239 layers = ds->playlist()->top_layer() + 1;
240 update_contents_y_position_and_height ();
243 redisplay_diskstream ();
247 playlist_connections.push_back (ds->playlist()->Modified.connect (bind (mem_fun (*this, &StreamView::playlist_modified_weak), ds)));
251 StreamView::diskstream_changed ()
253 boost::shared_ptr<Track> t;
255 if ((t = _trackview.track()) != 0) {
256 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*this, &StreamView::display_diskstream), t->diskstream()));
258 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::undisplay_diskstream));
263 StreamView::apply_color (Gdk::Color& color, ColorTarget target)
266 list<RegionView *>::iterator i;
270 region_color = color;
271 for (i = region_views.begin(); i != region_views.end(); ++i) {
272 (*i)->set_color (region_color);
276 case StreamBaseColor:
277 stream_base_color = RGBA_TO_UINT (
278 color.get_red_p(), color.get_green_p(), color.get_blue_p(), 255);
279 canvas_rect->property_fill_color_rgba() = stream_base_color;
285 StreamView::region_layered (RegionView* rv)
289 Currently 'layer' has nothing to do with the desired canvas layer.
290 For now, ensure that multiple regionviews passed here in groups are
291 ordered by 'layer' (lowest to highest).
293 (see AudioStreamView::redisplay_diskstream ()).
295 We move them to the top layer as they arrive.
298 rv->get_canvas_group()->raise_to_top();
302 StreamView::rec_enable_changed ()
304 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box));
308 StreamView::sess_rec_enable_changed ()
310 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box));
314 StreamView::transport_changed()
316 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box));
320 StreamView::transport_looped()
322 // to force a new rec region
324 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box));
328 StreamView::update_rec_box ()
330 if (rec_active && rec_rects.size() > 0) {
331 /* only update the last box */
332 RecBoxInfo & rect = rec_rects.back();
333 nframes_t at = _trackview.get_diskstream()->current_capture_end();
337 switch (_trackview.track()->mode()) {
339 rect.length = at - rect.start;
340 xstart = _trackview.editor.frame_to_pixel (rect.start);
341 xend = _trackview.editor.frame_to_pixel (at);
346 xstart = _trackview.editor.frame_to_pixel (_trackview.get_diskstream()->current_capture_start());
347 xend = _trackview.editor.frame_to_pixel (at);
351 rect.rectangle->property_x1() = xstart;
352 rect.rectangle->property_x2() = xend;
357 StreamView::find_view (boost::shared_ptr<const Region> region)
359 for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
361 if ((*i)->region() == region) {
369 StreamView::foreach_regionview (sigc::slot<void,RegionView*> slot)
371 for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
377 StreamView::set_selected_regionviews (RegionSelection& regions)
381 for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
385 for (RegionSelection::iterator ii = regions.begin(); ii != regions.end(); ++ii) {
391 (*i)->set_selected (selected);
396 StreamView::get_selectables (nframes_t start, nframes_t end, list<Selectable*>& results)
398 for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
399 if ((*i)->region()->coverage(start, end) != OverlapNone) {
400 results.push_back (*i);
406 StreamView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
408 for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
409 if (!sel.regions.contains (*i)) {
410 results.push_back (*i);
416 StreamView::update_contents_y_position_and_height ()
418 canvas_rect->property_y2() = height;
420 const double lh = height / layers;
422 for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
423 switch (layer_display) {
425 (*i)->set_y_position_and_height (0, height);
428 double const y = (*i)->region()->layer() * lh;
429 (*i)->set_y_position_and_height (y, lh);
434 for (vector<RecBoxInfo>::iterator i = rec_rects.begin(); i != rec_rects.end(); ++i) {
435 i->rectangle->property_y2() = height - 1.0;
440 StreamView::set_layer_display (LayerDisplay d)
443 update_contents_y_position_and_height ();