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 , owns_canvas_group(group == 0)
51 , canvas_group(group ? group : new ArdourCanvas::Group(*_trackview.canvas_display))
52 , canvas_rect(new ArdourCanvas::SimpleRect (*canvas_group))
53 , _samples_per_unit(_trackview.editor.get_current_zoom())
56 , use_rec_regions(tv.editor.show_waveforms_recording())
57 , region_color(_trackview.color())
58 , stream_base_color(0xFFFFFFFF)
61 , layer_display(Overlaid)
62 , last_rec_data_frame(0)
64 /* set_position() will position the 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 ();
92 if (owns_canvas_group) {
100 if (_trackview.is_track()) {
101 display_diskstream (_trackview.get_diskstream());
106 StreamView::set_position (gdouble x, gdouble y)
108 canvas_group->property_x() = x;
109 canvas_group->property_y() = y;
114 StreamView::set_height (double h)
116 /* limit the values to something sane-ish */
117 if (h < 10.0 || h > 1000.0) {
121 if (canvas_rect->property_y2() == h) {
126 update_contents_y_position_and_height ();
131 StreamView::set_samples_per_unit (gdouble spp)
133 RegionViewList::iterator i;
139 _samples_per_unit = spp;
141 for (i = region_views.begin(); i != region_views.end(); ++i) {
142 (*i)->set_samples_per_unit (spp);
145 for (vector<RecBoxInfo>::iterator xi = rec_rects.begin(); xi != rec_rects.end(); ++xi) {
146 RecBoxInfo &recbox = (*xi);
148 gdouble xstart = _trackview.editor.frame_to_pixel ( recbox.start );
149 gdouble xend = _trackview.editor.frame_to_pixel ( recbox.start + recbox.length );
151 recbox.rectangle->property_x1() = xstart;
152 recbox.rectangle->property_x2() = xend;
159 StreamView::add_region_view (boost::shared_ptr<Region> r)
161 // ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::add_region_view), r));
163 add_region_view_internal (r, true);
167 StreamView::remove_region_view (boost::weak_ptr<Region> weak_r)
169 ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::remove_region_view), weak_r));
171 boost::shared_ptr<Region> r (weak_r.lock());
177 for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
178 if (((*i)->region()) == r) {
180 region_views.erase (i);
188 StreamView::undisplay_diskstream ()
190 for (RegionViewList::iterator i = region_views.begin(); i != region_views.end() ; ) {
191 RegionViewList::iterator next = i;
197 region_views.clear();
201 StreamView::display_diskstream (boost::shared_ptr<Diskstream> ds)
203 playlist_change_connection.disconnect();
204 playlist_changed (ds);
205 playlist_change_connection = ds->PlaylistChanged.connect (bind (mem_fun (*this, &StreamView::playlist_changed), ds));
209 StreamView::playlist_modified_weak (boost::weak_ptr<Diskstream> ds)
211 boost::shared_ptr<Diskstream> sp (ds.lock());
216 playlist_modified (sp);
220 StreamView::playlist_modified (boost::shared_ptr<Diskstream> ds)
222 /* we do not allow shared_ptr<T> to be bound to slots */
223 ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::playlist_modified_weak), ds));
225 /* update layers count and the y positions and heights of our regions */
226 if (ds->playlist()) {
227 layers = ds->playlist()->top_layer() + 1;
228 update_contents_y_position_and_height ();
229 redisplay_diskstream ();
234 StreamView::playlist_changed (boost::shared_ptr<Diskstream> ds)
236 /* XXX: binding to a shared_ptr, is this ok? */
237 ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::playlist_changed), ds));
239 /* disconnect from old playlist */
241 for (vector<sigc::connection>::iterator i = playlist_connections.begin(); i != playlist_connections.end(); ++i) {
245 playlist_connections.clear();
246 undisplay_diskstream ();
248 /* update layers count and the y positions and heights of our regions */
249 layers = ds->playlist()->top_layer() + 1;
250 update_contents_y_position_and_height ();
253 redisplay_diskstream ();
257 playlist_connections.push_back (ds->playlist()->Modified.connect (bind (mem_fun (*this, &StreamView::playlist_modified_weak), ds)));
261 StreamView::diskstream_changed ()
263 boost::shared_ptr<Track> t;
265 if ((t = _trackview.track()) != 0) {
266 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*this, &StreamView::display_diskstream), t->diskstream()));
268 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::undisplay_diskstream));
273 StreamView::apply_color (Gdk::Color& color, ColorTarget target)
276 list<RegionView *>::iterator i;
280 region_color = color;
281 for (i = region_views.begin(); i != region_views.end(); ++i) {
282 (*i)->set_color (region_color);
286 case StreamBaseColor:
287 stream_base_color = RGBA_TO_UINT (
288 color.get_red_p(), color.get_green_p(), color.get_blue_p(), 255);
289 canvas_rect->property_fill_color_rgba() = stream_base_color;
295 StreamView::region_layered (RegionView* rv)
299 Currently 'layer' has nothing to do with the desired canvas layer.
300 For now, ensure that multiple regionviews passed here in groups are
301 ordered by 'layer' (lowest to highest).
303 (see AudioStreamView::redisplay_diskstream ()).
305 We move them to the top layer as they arrive.
308 rv->get_canvas_group()->raise_to_top();
312 StreamView::rec_enable_changed ()
314 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box));
318 StreamView::sess_rec_enable_changed ()
320 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box));
324 StreamView::transport_changed()
326 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box));
330 StreamView::transport_looped()
332 // to force a new rec region
334 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box));
338 StreamView::update_rec_box ()
340 if (rec_active && rec_rects.size() > 0) {
341 /* only update the last box */
342 RecBoxInfo & rect = rec_rects.back();
343 nframes_t at = _trackview.get_diskstream()->current_capture_end();
347 switch (_trackview.track()->mode()) {
349 rect.length = at - rect.start;
350 xstart = _trackview.editor.frame_to_pixel (rect.start);
351 xend = _trackview.editor.frame_to_pixel (at);
356 xstart = _trackview.editor.frame_to_pixel (_trackview.get_diskstream()->current_capture_start());
357 xend = _trackview.editor.frame_to_pixel (at);
361 rect.rectangle->property_x1() = xstart;
362 rect.rectangle->property_x2() = xend;
367 StreamView::find_view (boost::shared_ptr<const Region> region)
369 for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
371 if ((*i)->region() == region) {
379 StreamView::foreach_regionview (sigc::slot<void,RegionView*> slot)
381 for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
387 StreamView::set_selected_regionviews (RegionSelection& regions)
391 for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
395 for (RegionSelection::iterator ii = regions.begin(); ii != regions.end(); ++ii) {
401 (*i)->set_selected (selected);
406 StreamView::get_selectables (nframes_t start, nframes_t end, list<Selectable*>& results)
408 for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
409 if ((*i)->region()->coverage(start, end) != OverlapNone) {
410 results.push_back (*i);
416 StreamView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
418 for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
419 if (!sel.regions.contains (*i)) {
420 results.push_back (*i);
426 StreamView::update_contents_y_position_and_height ()
428 canvas_rect->property_y2() = height;
430 const double lh = height / layers;
432 for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
433 switch (layer_display) {
435 (*i)->set_y_position_and_height (0, height);
438 double const y = (*i)->region()->layer() * lh;
439 (*i)->set_y_position_and_height (y, lh);
444 for (vector<RecBoxInfo>::iterator i = rec_rects.begin(); i != rec_rects.end(); ++i) {
445 i->rectangle->property_y2() = height - 1.0;
450 StreamView::set_layer_display (LayerDisplay d)
453 update_contents_y_position_and_height ();