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 = new ArdourCanvas::SimpleRect (*canvas_group);
66 canvas_rect->property_x1() = 0.0;
67 canvas_rect->property_y1() = 0.0;
68 canvas_rect->property_x2() = _trackview.editor.frame_to_pixel (max_frames);
69 canvas_rect->property_y2() = (double) tv.height;
70 canvas_rect->property_outline_what() = (guint32) (0x2|0x8); // outline RHS and bottom
71 // (Fill/Outline colours set in derived classes)
73 canvas_rect->signal_event().connect (bind (mem_fun (_trackview.editor, &PublicEditor::canvas_stream_view_event), canvas_rect, &_trackview));
75 if (_trackview.is_track()) {
76 _trackview.track()->DiskstreamChanged.connect (mem_fun (*this, &StreamView::diskstream_changed));
77 _trackview.session().TransportStateChange.connect (mem_fun (*this, &StreamView::transport_changed));
78 _trackview.session().TransportLooped.connect (mem_fun (*this, &StreamView::transport_looped));
79 _trackview.get_diskstream()->RecordEnableChanged.connect (mem_fun (*this, &StreamView::rec_enable_changed));
80 _trackview.session().RecordStateChanged.connect (mem_fun (*this, &StreamView::sess_rec_enable_changed));
83 ColorsChanged.connect (mem_fun (*this, &StreamView::color_handler));
86 StreamView::~StreamView ()
88 undisplay_diskstream ();
95 if (_trackview.is_track()) {
96 display_diskstream (_trackview.get_diskstream());
101 StreamView::set_position (gdouble x, gdouble y)
103 canvas_group->property_x() = x;
104 canvas_group->property_y() = y;
109 StreamView::set_height (double h)
111 /* limit the values to something sane-ish */
112 if (h < 10.0 || h > 1000.0) {
116 if (canvas_rect->property_y2() == h) {
121 update_contents_y_position_and_height ();
126 StreamView::set_samples_per_unit (gdouble spp)
128 RegionViewList::iterator i;
134 _samples_per_unit = spp;
136 for (i = region_views.begin(); i != region_views.end(); ++i) {
137 (*i)->set_samples_per_unit (spp);
140 for (vector<RecBoxInfo>::iterator xi = rec_rects.begin(); xi != rec_rects.end(); ++xi) {
141 RecBoxInfo &recbox = (*xi);
143 gdouble xstart = _trackview.editor.frame_to_pixel ( recbox.start );
144 gdouble xend = _trackview.editor.frame_to_pixel ( recbox.start + recbox.length );
146 recbox.rectangle->property_x1() = xstart;
147 recbox.rectangle->property_x2() = xend;
154 StreamView::add_region_view (boost::shared_ptr<Region> r)
156 // ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::add_region_view), r));
158 add_region_view_internal (r, true);
162 StreamView::remove_region_view (boost::weak_ptr<Region> weak_r)
164 ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::remove_region_view), weak_r));
166 boost::shared_ptr<Region> r (weak_r.lock());
172 for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
173 if (((*i)->region()) == r) {
175 region_views.erase (i);
182 StreamView::undisplay_diskstream ()
184 for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
188 region_views.clear();
192 StreamView::display_diskstream (boost::shared_ptr<Diskstream> ds)
194 playlist_change_connection.disconnect();
195 playlist_changed (ds);
196 playlist_change_connection = ds->PlaylistChanged.connect (bind (mem_fun (*this, &StreamView::playlist_changed), ds));
200 StreamView::playlist_modified_weak (boost::weak_ptr<Diskstream> ds)
202 boost::shared_ptr<Diskstream> sp (ds.lock());
207 playlist_modified (sp);
211 StreamView::playlist_modified (boost::shared_ptr<Diskstream> ds)
213 /* we do not allow shared_ptr<T> to be bound to slots */
214 ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::playlist_modified_weak), ds));
216 /* update layers count and the y positions and heights of our regions */
217 if (ds->playlist()) {
218 layers = ds->playlist()->top_layer() + 1;
219 update_contents_y_position_and_height ();
220 redisplay_diskstream ();
225 StreamView::playlist_changed (boost::shared_ptr<Diskstream> ds)
227 /* XXX: binding to a shared_ptr, is this ok? */
228 ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::playlist_changed), ds));
230 /* disconnect from old playlist */
232 for (vector<sigc::connection>::iterator i = playlist_connections.begin(); i != playlist_connections.end(); ++i) {
236 playlist_connections.clear();
237 undisplay_diskstream ();
239 /* update layers count and the y positions and heights of our regions */
240 layers = ds->playlist()->top_layer() + 1;
241 update_contents_y_position_and_height ();
244 redisplay_diskstream ();
248 playlist_connections.push_back (ds->playlist()->Modified.connect (bind (mem_fun (*this, &StreamView::playlist_modified_weak), ds)));
252 StreamView::diskstream_changed ()
254 boost::shared_ptr<Track> t;
256 if ((t = _trackview.track()) != 0) {
257 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*this, &StreamView::display_diskstream), t->diskstream()));
259 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::undisplay_diskstream));
264 StreamView::apply_color (Gdk::Color& color, ColorTarget target)
267 list<RegionView *>::iterator i;
271 region_color = color;
272 for (i = region_views.begin(); i != region_views.end(); ++i) {
273 (*i)->set_color (region_color);
277 case StreamBaseColor:
278 stream_base_color = RGBA_TO_UINT (
279 color.get_red_p(), color.get_green_p(), color.get_blue_p(), 255);
280 canvas_rect->property_fill_color_rgba() = stream_base_color;
286 StreamView::region_layered (RegionView* rv)
290 Currently 'layer' has nothing to do with the desired canvas layer.
291 For now, ensure that multiple regionviews passed here in groups are
292 ordered by 'layer' (lowest to highest).
294 (see AudioStreamView::redisplay_diskstream ()).
296 We move them to the top layer as they arrive.
299 rv->get_canvas_group()->raise_to_top();
303 StreamView::rec_enable_changed ()
305 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box));
309 StreamView::sess_rec_enable_changed ()
311 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box));
315 StreamView::transport_changed()
317 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box));
321 StreamView::transport_looped()
323 // to force a new rec region
325 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box));
329 StreamView::update_rec_box ()
331 if (rec_active && rec_rects.size() > 0) {
332 /* only update the last box */
333 RecBoxInfo & rect = rec_rects.back();
334 nframes_t at = _trackview.get_diskstream()->current_capture_end();
338 switch (_trackview.track()->mode()) {
340 rect.length = at - rect.start;
341 xstart = _trackview.editor.frame_to_pixel (rect.start);
342 xend = _trackview.editor.frame_to_pixel (at);
347 xstart = _trackview.editor.frame_to_pixel (_trackview.get_diskstream()->current_capture_start());
348 xend = _trackview.editor.frame_to_pixel (at);
352 rect.rectangle->property_x1() = xstart;
353 rect.rectangle->property_x2() = xend;
358 StreamView::find_view (boost::shared_ptr<const Region> region)
360 for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
362 if ((*i)->region() == region) {
370 StreamView::foreach_regionview (sigc::slot<void,RegionView*> slot)
372 for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
378 StreamView::set_selected_regionviews (RegionSelection& regions)
382 // cerr << _trackview.name() << " (selected = " << regions.size() << ")" << endl;
383 for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
387 for (RegionSelection::iterator ii = regions.begin(); ii != regions.end(); ++ii) {
393 // cerr << "\tregion " << (*i)->region().name() << " selected = " << selected << endl;
394 (*i)->set_selected (selected);
399 StreamView::get_selectables (nframes_t start, nframes_t end, list<Selectable*>& results)
401 for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
402 if ((*i)->region()->coverage(start, end) != OverlapNone) {
403 results.push_back (*i);
409 StreamView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
411 for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
412 if (!sel.regions.contains (*i)) {
413 results.push_back (*i);
419 StreamView::update_contents_y_position_and_height ()
421 canvas_rect->property_y2() = height;
423 const double lh = height / layers;
425 for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
426 switch (layer_display) {
428 (*i)->set_y_position_and_height (0, height);
431 double const y = (*i)->region()->layer() * lh;
432 (*i)->set_y_position_and_height (y, lh);
437 for (vector<RecBoxInfo>::iterator i = rec_rects.begin(); i != rec_rects.end(); ++i) {
438 i->rectangle->property_y2() = height - 1.0;
443 StreamView::set_layer_display (LayerDisplay d)
446 update_contents_y_position_and_height ();