summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <carl@carlh.net>2007-05-17 10:41:14 +0000
committerCarl Hetherington <carl@carlh.net>2007-05-17 10:41:14 +0000
commitef65fd251023378699c3ef3842fc55e93a92d04a (patch)
tree0b8c18d48355c9e5048a3ab6ea303b7268d9d1c5
parent06fd14b0850c8d043ae568c3d1f34460218d879f (diff)
Add stacked lanes mode which displays regions on different layers at different positions in the view.
git-svn-id: svn://localhost/ardour2/trunk@1855 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--gtk2_ardour/audio_region_view.cc72
-rw-r--r--gtk2_ardour/audio_region_view.h8
-rw-r--r--gtk2_ardour/audio_streamview.cc57
-rw-r--r--gtk2_ardour/audio_streamview.h6
-rw-r--r--gtk2_ardour/audio_time_axis.cc20
-rw-r--r--gtk2_ardour/audio_time_axis.h1
-rw-r--r--gtk2_ardour/automation_line.cc33
-rw-r--r--gtk2_ardour/automation_line.h4
-rw-r--r--gtk2_ardour/automation_time_axis.cc4
-rw-r--r--gtk2_ardour/crossfade_view.cc26
-rw-r--r--gtk2_ardour/crossfade_view.h4
-rw-r--r--gtk2_ardour/editor_mouse.cc19
-rw-r--r--gtk2_ardour/enums.h5
-rw-r--r--gtk2_ardour/marker_time_axis_view.cc10
-rw-r--r--gtk2_ardour/midi_region_view.cc2
-rw-r--r--gtk2_ardour/region_view.cc14
-rw-r--r--gtk2_ardour/region_view.h2
-rw-r--r--gtk2_ardour/streamview.cc76
-rw-r--r--gtk2_ardour/streamview.h12
-rw-r--r--gtk2_ardour/time_axis_view_item.cc27
-rw-r--r--gtk2_ardour/time_axis_view_item.h7
21 files changed, 260 insertions, 149 deletions
diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc
index 2e1c13b487..bc0e3671c3 100644
--- a/gtk2_ardour/audio_region_view.cc
+++ b/gtk2_ardour/audio_region_view.cc
@@ -157,20 +157,18 @@ AudioRegionView::init (Gdk::Color& basic_color, bool wfd)
fade_in_handle = new ArdourCanvas::SimpleRect (*group);
fade_in_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,0);
fade_in_handle->property_outline_pixels() = 0;
- fade_in_handle->property_y1() = 2.0;
- fade_in_handle->property_y2() = 7.0;
fade_in_handle->set_data ("regionview", this);
fade_out_handle = new ArdourCanvas::SimpleRect (*group);
fade_out_handle->property_fill_color_rgba() = RGBA_TO_UINT(r,g,b,0);
fade_out_handle->property_outline_pixels() = 0;
- fade_out_handle->property_y1() = 2.0;
- fade_out_handle->property_y2() = 7.0;
fade_out_handle->set_data ("regionview", this);
}
+ setup_fade_handle_positions ();
+
string foo = _region->name();
foo += ':';
foo += "gain";
@@ -185,7 +183,7 @@ AudioRegionView::init (Gdk::Color& basic_color, bool wfd)
gain_line->reset ();
- set_height (trackview.height);
+ set_y_position_and_height (0, trackview.height);
region_muted ();
region_sync_changed ();
@@ -400,38 +398,41 @@ AudioRegionView::region_muted ()
}
void
-AudioRegionView::set_height (gdouble height)
+AudioRegionView::set_y_position_and_height (double y, double h)
{
- RegionView::set_height(height);
-
- uint32_t wcnt = waves.size();
+ RegionView::set_y_position_and_height(y, h - 2);
+
+ _y_position = y;
+ _height = h;
- for (uint32_t n=0; n < wcnt; ++n) {
- gdouble ht;
+ uint32_t const wcnt = waves.size();
+ for (uint32_t n = 0; n < wcnt; ++n) {
+ double ht;
- if ((height) <= NAME_HIGHLIGHT_THRESH) {
- ht = ((height-2*wcnt) / (double) wcnt);
+ if (h <= NAME_HIGHLIGHT_THRESH) {
+ ht = ((_height - 2 * wcnt) / (double) wcnt);
} else {
- ht = (((height-2*wcnt) - NAME_HIGHLIGHT_SIZE) / (double) wcnt);
+ ht = (((_height - 2 * wcnt) - NAME_HIGHLIGHT_SIZE) / (double) wcnt);
}
- gdouble yoff = n * (ht+1);
+ double const yoff = n * (ht + 1);
waves[n]->property_height() = ht;
- waves[n]->property_y() = yoff + 2;
+ waves[n]->property_y() = _y_position + yoff + 2;
}
if (gain_line) {
- if ((height/wcnt) < NAME_HIGHLIGHT_SIZE) {
+ if ((_height / wcnt) < NAME_HIGHLIGHT_SIZE) {
gain_line->hide ();
} else {
if (_flags & EnvelopeVisible) {
gain_line->show ();
}
}
- gain_line->set_height ((uint32_t) rint (height - NAME_HIGHLIGHT_SIZE));
+ gain_line->set_y_position_and_height ((uint32_t) _y_position, (uint32_t) rint (_height - NAME_HIGHLIGHT_SIZE));
}
+ setup_fade_handle_positions ();
manage_zero_line ();
reset_fade_shapes ();
@@ -441,6 +442,25 @@ AudioRegionView::set_height (gdouble height)
}
void
+AudioRegionView::setup_fade_handle_positions()
+{
+ /* position of fade handle offset from the top of the region view */
+ double const handle_pos = 2;
+ /* height of fade handles */
+ double const handle_height = 5;
+
+ if (fade_in_handle) {
+ fade_in_handle->property_y1() = _y_position + handle_pos;
+ fade_in_handle->property_y2() = _y_position + handle_pos + handle_height;
+ }
+
+ if (fade_out_handle) {
+ fade_out_handle->property_y1() = _y_position + handle_pos;
+ fade_out_handle->property_y2() = _y_position + handle_pos + handle_height;
+ }
+}
+
+void
AudioRegionView::manage_zero_line ()
{
if (!zero_line) {
@@ -448,7 +468,7 @@ AudioRegionView::manage_zero_line ()
}
if (_height >= 100) {
- gdouble wave_midpoint = (_height - NAME_HIGHLIGHT_SIZE) / 2.0;
+ double const wave_midpoint = _y_position + (_height - NAME_HIGHLIGHT_SIZE) / 2.0;
zero_line->property_y1() = wave_midpoint;
zero_line->property_y2() = wave_midpoint;
zero_line->show();
@@ -529,16 +549,16 @@ AudioRegionView::reset_fade_in_shape_width (nframes_t width)
for (pi = 0, pc = 0; pc < npoints; ++pc) {
(*points)[pi].set_x(1 + (pc * xdelta));
- (*points)[pi++].set_y(2 + (h - (curve[pc] * h)));
+ (*points)[pi++].set_y(_y_position + 2 + (h - (curve[pc] * h)));
}
/* fold back */
(*points)[pi].set_x(pwidth);
- (*points)[pi++].set_y(2);
+ (*points)[pi++].set_y(_y_position + 2);
(*points)[pi].set_x(1);
- (*points)[pi++].set_y(2);
+ (*points)[pi++].set_y(_y_position + 2);
/* connect the dots ... */
@@ -615,16 +635,16 @@ AudioRegionView::reset_fade_out_shape_width (nframes_t width)
for (pi = 0, pc = 0; pc < npoints; ++pc) {
(*points)[pi].set_x(_pixel_width - 1 - pwidth + (pc*xdelta));
- (*points)[pi++].set_y(2 + (h - (curve[pc] * h)));
+ (*points)[pi++].set_y(_y_position + 2 + (h - (curve[pc] * h)));
}
/* fold back */
(*points)[pi].set_x(_pixel_width);
- (*points)[pi++].set_y(h);
+ (*points)[pi++].set_y(_y_position + h);
(*points)[pi].set_x(_pixel_width);
- (*points)[pi++].set_y(2);
+ (*points)[pi++].set_y(_y_position + 2);
/* connect the dots ... */
@@ -912,7 +932,7 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev)
/* compute vertical fractional position */
- y = 1.0 - (y / (trackview.height - NAME_HIGHLIGHT_SIZE));
+ y = 1.0 - ((y - _y_position) / (_height - NAME_HIGHLIGHT_SIZE));
/* map using gain line */
diff --git a/gtk2_ardour/audio_region_view.h b/gtk2_ardour/audio_region_view.h
index 233e1a7c9b..e581e01146 100644
--- a/gtk2_ardour/audio_region_view.h
+++ b/gtk2_ardour/audio_region_view.h
@@ -63,7 +63,7 @@ class AudioRegionView : public RegionView
boost::shared_ptr<ARDOUR::AudioRegion> audio_region() const;
- void set_height (double);
+ void set_y_position_and_height (double, double);
void set_samples_per_unit (double);
void set_amplitude_above_axis (gdouble spp);
@@ -132,6 +132,8 @@ class AudioRegionView : public RegionView
AudioRegionGainLine * gain_line;
double _amplitude_above_axis;
+ double _y_position;
+ double _height;
uint32_t _flags;
uint32_t fade_color;
@@ -165,6 +167,10 @@ class AudioRegionView : public RegionView
void color_handler (ColorID, uint32_t);
vector<GnomeCanvasWaveViewCache*> wave_caches;
+
+ private:
+
+ void setup_fade_handle_positions ();
};
#endif /* __gtk_ardour_audio_region_view_h__ */
diff --git a/gtk2_ardour/audio_streamview.cc b/gtk2_ardour/audio_streamview.cc
index db7b07dfb2..4ca3ad38b9 100644
--- a/gtk2_ardour/audio_streamview.cc
+++ b/gtk2_ardour/audio_streamview.cc
@@ -79,23 +79,6 @@ AudioStreamView::~AudioStreamView ()
{
}
-int
-AudioStreamView::set_height (gdouble h)
-{
- /* limit the values to something sane-ish */
- if (h < 10.0 || h > 1000.0) {
- return -1;
- }
-
- StreamView::set_height(h);
-
- for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
- (*i)->set_height (h);
- }
-
- return 0;
-}
-
int
AudioStreamView::set_samples_per_unit (gdouble spp)
{
@@ -263,11 +246,23 @@ AudioStreamView::undisplay_diskstream ()
}
void
-AudioStreamView::playlist_modified ()
+AudioStreamView::playlist_modified_weak (boost::weak_ptr<Diskstream> ds)
{
- ENSURE_GUI_THREAD (mem_fun (*this, &AudioStreamView::playlist_modified));
+ boost::shared_ptr<Diskstream> sp (ds.lock());
+ if (!sp) {
+ return;
+ }
- StreamView::playlist_modified();
+ playlist_modified (sp);
+}
+
+void
+AudioStreamView::playlist_modified (boost::shared_ptr<Diskstream> ds)
+{
+ /* we do not allow shared_ptr<T> to be bound to slots */
+ ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::playlist_modified_weak), ds));
+
+ StreamView::playlist_modified (ds);
/* make sure xfades are on top and all the regionviews are stacked correctly. */
@@ -314,7 +309,7 @@ AudioStreamView::add_crossfade (boost::shared_ptr<Crossfade> crossfade)
for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
if ((*i)->crossfade == crossfade) {
- if (!crossfades_visible) {
+ if (!crossfades_visible || layer_display == Stacked) {
(*i)->hide();
} else {
(*i)->show ();
@@ -347,7 +342,7 @@ AudioStreamView::add_crossfade (boost::shared_ptr<Crossfade> crossfade)
crossfade->Invalidated.connect (mem_fun (*this, &AudioStreamView::remove_crossfade));
crossfade_views.push_back (cv);
- if (!Config->get_xfades_visible() || !crossfades_visible) {
+ if (!Config->get_xfades_visible() || !crossfades_visible || layer_display == Stacked) {
cv->hide ();
}
}
@@ -378,7 +373,7 @@ AudioStreamView::redisplay_diskstream ()
for (xi = crossfade_views.begin(); xi != crossfade_views.end(); ++xi) {
(*xi)->set_valid (false);
- if ((*xi)->visible()) {
+ if ((*xi)->visible() && layer_display != Stacked) {
(*xi)->show ();
}
}
@@ -755,7 +750,7 @@ void
AudioStreamView::reveal_xfades_involving (AudioRegionView& rv)
{
for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
- if ((*i)->crossfade->involves (rv.audio_region()) && (*i)->visible()) {
+ if ((*i)->crossfade->involves (rv.audio_region()) && (*i)->visible() && layer_display != Stacked) {
(*i)->show ();
}
}
@@ -784,3 +779,17 @@ AudioStreamView::color_handler (ColorID id, uint32_t val)
}
}
+void
+AudioStreamView::update_contents_y_position_and_height ()
+{
+ StreamView::update_contents_y_position_and_height ();
+
+ for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
+ if (layer_display == Overlaid) {
+ (*i)->show ();
+ (*i)->set_y_position_and_height (0, height);
+ } else {
+ (*i)->hide ();
+ }
+ }
+}
diff --git a/gtk2_ardour/audio_streamview.h b/gtk2_ardour/audio_streamview.h
index 9f3630c182..fc707e97e7 100644
--- a/gtk2_ardour/audio_streamview.h
+++ b/gtk2_ardour/audio_streamview.h
@@ -63,7 +63,6 @@ class AudioStreamView : public StreamView
void set_waveform_scale (WaveformScale);
WaveformScale get_waveform_scale () const { return _waveform_scale; }
- int set_height (gdouble h);
int set_samples_per_unit (gdouble spp);
int set_amplitude_above_axis (gdouble app);
@@ -90,7 +89,8 @@ class AudioStreamView : public StreamView
void undisplay_diskstream ();
void redisplay_diskstream ();
- void playlist_modified ();
+ void playlist_modified_weak (boost::weak_ptr<ARDOUR::Diskstream>);
+ void playlist_modified (boost::shared_ptr<ARDOUR::Diskstream>);
void playlist_changed (boost::shared_ptr<ARDOUR::Diskstream>);
void add_crossfade (boost::shared_ptr<ARDOUR::Crossfade>);
@@ -98,6 +98,8 @@ class AudioStreamView : public StreamView
void remove_crossfade (boost::shared_ptr<ARDOUR::Crossfade>);
void color_handler (ColorID id, uint32_t val);
+
+ void update_contents_y_position_and_height ();
double _amplitude_above_axis;
diff --git a/gtk2_ardour/audio_time_axis.cc b/gtk2_ardour/audio_time_axis.cc
index 414329f145..d37b164ed1 100644
--- a/gtk2_ardour/audio_time_axis.cc
+++ b/gtk2_ardour/audio_time_axis.cc
@@ -287,6 +287,18 @@ AudioTimeAxisView::append_extra_display_menu_items ()
}
items.push_back (MenuElem (_("Waveform"), *waveform_menu));
+
+
+ Menu *layers_menu = manage(new Menu);
+ MenuList &layers_items = layers_menu->items();
+ layers_menu->set_name("ArdourContextMenu");
+
+ RadioMenuItem::Group layers_group;
+
+ layers_items.push_back(RadioMenuElem (layers_group, _("Overlaid"), bind (mem_fun (*this, &AudioTimeAxisView::set_layer_display), Overlaid)));
+ layers_items.push_back(RadioMenuElem (layers_group, _("Stacked"), bind (mem_fun (*this, &AudioTimeAxisView::set_layer_display), Stacked)));
+
+ items.push_back (MenuElem (_("Layers"), *layers_menu));
}
void
@@ -663,3 +675,11 @@ AudioTimeAxisView::get_child_xml_node (const string & childname)
return RouteUI::get_child_xml_node (childname);
}
+void
+AudioTimeAxisView::set_layer_display (LayerDisplay d)
+{
+ AudioStreamView* asv = audio_view ();
+ if (asv) {
+ asv->set_layer_display (d);
+ }
+}
diff --git a/gtk2_ardour/audio_time_axis.h b/gtk2_ardour/audio_time_axis.h
index d8c3f07cc1..ab5ef955c7 100644
--- a/gtk2_ardour/audio_time_axis.h
+++ b/gtk2_ardour/audio_time_axis.h
@@ -77,6 +77,7 @@ class AudioTimeAxisView : public RouteTimeAxisView
void hide_all_xfades ();
void hide_dependent_views (TimeAxisViewItem&);
void reveal_dependent_views (TimeAxisViewItem&);
+ void set_layer_display (LayerDisplay d);
/* Overridden from parent to store display state */
guint32 show_at (double y, int& nth, Gtk::VBox *parent);
diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc
index 67f91e1ed4..a729161911 100644
--- a/gtk2_ardour/automation_line.cc
+++ b/gtk2_ardour/automation_line.cc
@@ -232,6 +232,7 @@ AutomationLine::AutomationLine (const string & name, TimeAxisView& tv, ArdourCan
no_draw = false;
_visible = true;
terminal_points_can_slide = true;
+ _y_position = 0;
_height = 0;
group = new ArdourCanvas::Group (parent);
@@ -307,17 +308,27 @@ AutomationLine::control_point_box_size ()
}
void
-AutomationLine::set_height (guint32 h)
+AutomationLine::set_y_position_and_height (guint32 y, guint32 h)
{
+ bool changed = false;
+
+ if (y != _y_position) {
+ _y_position = y;
+ changed = true;
+ }
+
if (h != _height) {
_height = h;
- double bsz = control_point_box_size();
+ double const bsz = control_point_box_size();
for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
(*i)->set_size (bsz);
}
+ changed = true;
+ }
+ if (changed) {
reset ();
}
}
@@ -365,7 +376,7 @@ AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool wi
y = max (0.0, y);
y = min (1.0, y);
- y = _height - (y * _height);
+ y = _y_position + _height - (y * _height);
if (cp.can_slide) {
@@ -494,7 +505,7 @@ AutomationLine::model_representation (ControlPoint& cp, ModelRepresentation& mr)
*/
mr.xval = (nframes_t) floor (cp.get_x());
- mr.yval = 1.0 - (cp.get_y() / _height);
+ mr.yval = 1.0 - ( (cp.get_y() - _y_position) / _height);
/* if xval has not changed, set it directly from the model to avoid rounding errors */
@@ -831,7 +842,7 @@ AutomationLine::point_drag (ControlPoint& cp, nframes_t x, float fraction, bool
void
AutomationLine::line_drag (uint32_t i1, uint32_t i2, float fraction, bool with_push)
{
- double ydelta = fraction - last_drag_fraction;
+ double const ydelta = fraction - last_drag_fraction;
did_push = with_push;
@@ -844,7 +855,7 @@ AutomationLine::line_drag (uint32_t i1, uint32_t i2, float fraction, bool with_p
for (uint32_t i = i1 ; i <= i2; i++) {
cp = nth (i);
- modify_view_point (*cp, trackview.editor.unit_to_frame (cp->get_x()), ((_height - cp->get_y()) /_height) + ydelta, with_push);
+ modify_view_point (*cp, trackview.editor.unit_to_frame (cp->get_x()), ((_height - cp->get_y() + _y_position) /_height) + ydelta, with_push);
}
if (line_points.size() > 1) {
@@ -1041,8 +1052,8 @@ AutomationLine::get_selectables (nframes_t& start, nframes_t& end,
/* Curse X11 and its inverted coordinate system! */
- bot = (1.0 - topfrac) * _height;
- top = (1.0 - botfrac) * _height;
+ bot = _y_position + (1.0 - topfrac) * _height;
+ top = _y_position + (1.0 - botfrac) * _height;
nstart = max_frames;
nend = 0;
@@ -1108,8 +1119,8 @@ AutomationLine::set_selected_points (PointSelection& points)
/* Curse X11 and its inverted coordinate system! */
- bot = (1.0 - (*r).high_fract) * _height;
- top = (1.0 - (*r).low_fract) * _height;
+ bot = _y_position + (1.0 - (*r).high_fract) * _height;
+ top = _y_position + (1.0 - (*r).low_fract) * _height;
for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
@@ -1203,7 +1214,7 @@ AutomationLine::reset_callback (const AutomationList& events)
model_to_view_y (translated_y);
tmp_points.push_back (ALPoint (trackview.editor.frame_to_unit ((*ai)->when),
- _height - (translated_y * _height)));
+ _y_position + _height - (translated_y * _height)));
}
determine_visible_control_points (tmp_points);
diff --git a/gtk2_ardour/automation_line.h b/gtk2_ardour/automation_line.h
index 76afff5097..2637a0c554 100644
--- a/gtk2_ardour/automation_line.h
+++ b/gtk2_ardour/automation_line.h
@@ -127,13 +127,14 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulThingWithGoin
string name() const { return _name; }
bool visible() const { return _visible; }
guint32 height() const { return _height; }
+ guint32 y_position() const { return _y_position; }
void set_line_color (uint32_t);
uint32_t get_line_color() const { return _line_color; }
void show ();
void hide ();
- void set_height (guint32);
+ void set_y_position_and_height (uint32_t, uint32_t);
void set_verbose_cursor_uses_gain_mapping (bool yn);
TimeAxisView& trackview;
@@ -164,6 +165,7 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulThingWithGoin
protected:
string _name;
+ guint32 _y_position;
guint32 _height;
uint32_t _line_color;
ARDOUR::AutomationList& alist;
diff --git a/gtk2_ardour/automation_time_axis.cc b/gtk2_ardour/automation_time_axis.cc
index 12998ee7d6..45103ec7f1 100644
--- a/gtk2_ardour/automation_time_axis.cc
+++ b/gtk2_ardour/automation_time_axis.cc
@@ -313,7 +313,7 @@ AutomationTimeAxisView::set_height (TrackHeight ht)
base_rect->property_y2() = h;
for (vector<AutomationLine*>::iterator i = lines.begin(); i != lines.end(); ++i) {
- (*i)->set_height (h);
+ (*i)->set_y_position_and_height (0, h);
}
for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
@@ -771,7 +771,7 @@ AutomationTimeAxisView::add_line (AutomationLine& line)
}
lines.push_back (&line);
- line.set_height (height);
+ line.set_y_position_and_height (0, height);
if (get) {
/* pick up the current state */
diff --git a/gtk2_ardour/crossfade_view.cc b/gtk2_ardour/crossfade_view.cc
index ef43ee9873..261b2b3ca4 100644
--- a/gtk2_ardour/crossfade_view.cc
+++ b/gtk2_ardour/crossfade_view.cc
@@ -68,7 +68,7 @@ CrossfadeView::CrossfadeView (ArdourCanvas::Group *parent,
fade_out->property_fill_color_rgba() = color_map[cCrossfadeLine];
fade_out->property_width_pixels() = 1;
- set_height (get_time_axis_view().height);
+ set_y_position_and_height (0, get_time_axis_view().height);
/* no frame around the xfade or overlap rects */
@@ -105,13 +105,16 @@ CrossfadeView::reset_width_dependent_items (double pixel_width)
}
void
-CrossfadeView::set_height (double height)
+CrossfadeView::set_y_position_and_height (double y, double h)
{
- if (height == TimeAxisView::hSmaller ||
- height == TimeAxisView::hSmall)
- TimeAxisViewItem::set_height (height - 3 );
- else
- TimeAxisViewItem::set_height (height - NAME_HIGHLIGHT_SIZE - 3 );
+ if (h == TimeAxisView::hSmaller || h == TimeAxisView::hSmall) {
+ TimeAxisViewItem::set_y_position_and_height (y, h - 3 );
+ } else {
+ TimeAxisViewItem::set_y_position_and_height (y, h - NAME_HIGHLIGHT_SIZE - 3 );
+ }
+
+ _y_position = y;
+ _height = h;
redraw_curves ();
}
@@ -158,9 +161,8 @@ CrossfadeView::redraw_curves ()
At "height - 3.0" the bottom of the crossfade touches the name highlight or the bottom of the track (if the
track is either Small or Smaller.
*/
- double tav_height = get_time_axis_view().height;
- if (tav_height == TimeAxisView::hSmaller ||
- tav_height == TimeAxisView::hSmall) {
+ double const tav_height = get_time_axis_view().height;
+ if (tav_height == TimeAxisView::hSmaller || tav_height == TimeAxisView::hSmall) {
h = tav_height - 3.0;
} else {
h = tav_height - NAME_HIGHLIGHT_SIZE - 3.0;
@@ -190,7 +192,7 @@ CrossfadeView::redraw_curves ()
for (int i = 0, pci = 0; i < npoints; ++i) {
Art::Point &p = (*points)[pci++];
p.set_x(i);
- p.set_y(2.0 + h - (h * vec[i]));
+ p.set_y(_y_position + 2.0 + h - (h * vec[i]));
}
fade_in->property_points() = *points;
@@ -198,7 +200,7 @@ CrossfadeView::redraw_curves ()
for (int i = 0, pci = 0; i < npoints; ++i) {
Art::Point &p = (*points)[pci++];
p.set_x(i);
- p.set_y(2.0 + h - (h * vec[i]));
+ p.set_y(_y_position + 2.0 + h - (h * vec[i]));
}
fade_out->property_points() = *points;
diff --git a/gtk2_ardour/crossfade_view.h b/gtk2_ardour/crossfade_view.h
index 556d8c80c5..02f3cd0df2 100644
--- a/gtk2_ardour/crossfade_view.h
+++ b/gtk2_ardour/crossfade_view.h
@@ -46,7 +46,7 @@ struct CrossfadeView : public TimeAxisViewItem
AudioRegionView& left_view; // and these too
AudioRegionView& right_view;
- void set_height (double);
+ void set_y_position_and_height (double, double);
bool valid() const { return _valid; }
bool visible() const { return _visible; }
@@ -68,6 +68,8 @@ struct CrossfadeView : public TimeAxisViewItem
bool _visible;
double spu;
+ double _y_position;
+ double _height;
ArdourCanvas::Item *overlap_rect;
ArdourCanvas::Line *fade_in;
diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc
index 4f06562fb0..5247b596b6 100644
--- a/gtk2_ardour/editor_mouse.cc
+++ b/gtk2_ardour/editor_mouse.cc
@@ -1066,7 +1066,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
at_x += 20.0;
at_y += 20.0;
- fraction = 1.0 - (cp->get_y() / cp->line.height());
+ fraction = 1.0 - ((cp->get_y() - cp->line.y_position()) / cp->line.height());
set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
show_verbose_canvas_cursor ();
@@ -2446,7 +2446,7 @@ void
Editor::start_control_point_grab (ArdourCanvas::Item* item, GdkEvent* event)
{
ControlPoint* control_point;
-
+
if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
/*NOTREACHED*/
@@ -2461,7 +2461,7 @@ Editor::start_control_point_grab (ArdourCanvas::Item* item, GdkEvent* event)
control_point->line.start_drag (control_point, drag_info.grab_frame, 0);
- float fraction = 1.0 - (control_point->get_y() / control_point->line.height());
+ float fraction = 1.0 - ((control_point->get_y() - control_point->line.y_position()) / control_point->line.height());
set_verbose_canvas_cursor (control_point->line.get_verbose_cursor_string (fraction),
drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
@@ -2490,7 +2490,7 @@ Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent*
cx = max (0.0, cx);
cy = max (0.0, cy);
- cy = min ((double) cp->line.height(), cy);
+ cy = min ((double) (cp->line.y_position() + cp->line.height()), cy);
//translate cx to frames
nframes_t cx_frames = unit_to_frame (cx);
@@ -2499,8 +2499,8 @@ Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent*
snap_to (cx_frames);
}
- float fraction = 1.0 - (cy / cp->line.height());
-
+ float const fraction = 1.0 - ((cy - cp->line.y_position()) / cp->line.height());
+
bool push;
if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
@@ -2590,7 +2590,7 @@ Editor::start_line_grab (AutomationLine* line, GdkEvent* event)
start_grab (event, fader_cursor);
- double fraction = 1.0 - (cy / line->height());
+ double const fraction = 1.0 - ((cy - line->y_position()) / line->height());
line->start_drag (0, drag_info.grab_frame, fraction);
@@ -2608,8 +2608,7 @@ Editor::line_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
line->parent_group().w2i (cx, cy);
- double fraction;
- fraction = 1.0 - (cy / line->height());
+ double const fraction = 1.0 - ((cy - line->y_position()) / line->height());
bool push;
@@ -3140,7 +3139,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
tvp2 = trackview_by_y_position (iy1 + y_delta);
temp_rtv = dynamic_cast<RouteTimeAxisView*>(tvp2);
- rv->set_height (temp_rtv->height);
+ rv->set_y_position_and_height (0, temp_rtv->height);
/* if you un-comment the following, the region colours will follow the track colours whilst dragging,
personally, i think this can confuse things, but never mind.
diff --git a/gtk2_ardour/enums.h b/gtk2_ardour/enums.h
index d345b30bf8..fcb675fd46 100644
--- a/gtk2_ardour/enums.h
+++ b/gtk2_ardour/enums.h
@@ -44,6 +44,11 @@ namespace Gnome {
}
}
+enum LayerDisplay {
+ Overlaid,
+ Stacked
+};
+
struct SelectionRect {
Gnome::Canvas::SimpleRect *rect;
Gnome::Canvas::SimpleRect *end_trim;
diff --git a/gtk2_ardour/marker_time_axis_view.cc b/gtk2_ardour/marker_time_axis_view.cc
index f33e0bbefc..34acf51fbf 100644
--- a/gtk2_ardour/marker_time_axis_view.cc
+++ b/gtk2_ardour/marker_time_axis_view.cc
@@ -115,16 +115,14 @@ MarkerTimeAxisView::~MarkerTimeAxisView()
int
MarkerTimeAxisView::set_height(gdouble h)
{
- if (h < 10.0 || h > 1000.0)
- {
- return -1 ;
+ if (h < 10.0 || h > 1000.0) {
+ return -1;
}
canvas_rect->property_y2() = h;
- for (MarkerViewList::iterator i = marker_view_list.begin(); i != marker_view_list.end(); ++i)
- {
- (*i)->set_height(h) ;
+ for (MarkerViewList::iterator i = marker_view_list.begin(); i != marker_view_list.end(); ++i) {
+ (*i)->set_y_position_and_height(0, h);
}
return 0;
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index c225295f13..cef1329ed5 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -75,7 +75,7 @@ MidiRegionView::init (Gdk::Color& basic_color, bool wfd)
reset_width_dependent_items ((double) _region->length() / samples_per_unit);
- set_height (trackview.height);
+ set_y_position_and_height (0, trackview.height);
region_muted ();
region_resized (BoundsChanged);
diff --git a/gtk2_ardour/region_view.cc b/gtk2_ardour/region_view.cc
index 859e2edfb4..3923f7e79a 100644
--- a/gtk2_ardour/region_view.cc
+++ b/gtk2_ardour/region_view.cc
@@ -72,7 +72,6 @@ RegionView::RegionView (ArdourCanvas::Group* parent,
, current_visible_sync_position(0.0)
, valid(false)
, _pixel_width(1.0)
- , _height(1.0)
, in_destructor(false)
, wait_for_data(false)
{
@@ -88,7 +87,6 @@ RegionView::RegionView (const RegionView& other)
current_visible_sync_position = other.current_visible_sync_position;
valid = false;
_pixel_width = other._pixel_width;
- _height = other._height;
}
RegionView::RegionView (ArdourCanvas::Group* parent,
@@ -104,7 +102,6 @@ RegionView::RegionView (ArdourCanvas::Group* parent,
, current_visible_sync_position(0.0)
, valid(false)
, _pixel_width(1.0)
- , _height(1.0)
, in_destructor(false)
, wait_for_data(false)
{
@@ -115,7 +112,6 @@ RegionView::init (Gdk::Color& basic_color, bool wfd)
{
valid = true;
in_destructor = false;
- _height = 0;
wait_for_data = wfd;
compute_colors (basic_color);
@@ -141,7 +137,7 @@ RegionView::init (Gdk::Color& basic_color, bool wfd)
reset_width_dependent_items ((double) _region->length() / samples_per_unit);
- set_height (trackview.height);
+ set_y_position_and_height (0, trackview.height);
_region->StateChanged.connect (mem_fun(*this, &RegionView::region_changed));
@@ -255,14 +251,6 @@ RegionView::reset_width_dependent_items (double pixel_width)
}
void
-RegionView::set_height (gdouble height)
-{
- TimeAxisViewItem::set_height (height - 2);
-
- _height = height;
-}
-
-void
RegionView::region_layered ()
{
RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*>(&get_time_axis_view());
diff --git a/gtk2_ardour/region_view.h b/gtk2_ardour/region_view.h
index 0f4d57ad04..d16d81e373 100644
--- a/gtk2_ardour/region_view.h
+++ b/gtk2_ardour/region_view.h
@@ -60,7 +60,6 @@ class RegionView : public TimeAxisViewItem
void set_valid (bool yn) { valid = yn; }
- virtual void set_height (double);
virtual void set_samples_per_unit (double);
virtual bool set_duration (nframes_t, void*);
@@ -134,7 +133,6 @@ class RegionView : public TimeAxisViewItem
bool valid; ///< see StreamView::redisplay_diskstream()
double _pixel_width;
- double _height;
bool in_destructor;
bool wait_for_data;
diff --git a/gtk2_ardour/streamview.cc b/gtk2_ardour/streamview.cc
index d6f2edeba9..2997661848 100644
--- a/gtk2_ardour/streamview.cc
+++ b/gtk2_ardour/streamview.cc
@@ -56,6 +56,7 @@ StreamView::StreamView (RouteTimeAxisView& tv)
, use_rec_regions(tv.editor.show_waveforms_recording())
, region_color(_trackview.color())
, stream_base_color(0xFFFFFFFF)
+ , layers(1)
, last_rec_data_frame(0)
{
/* set_position() will position the group */
@@ -96,7 +97,6 @@ StreamView::attach ()
int
StreamView::set_position (gdouble x, gdouble y)
-
{
canvas_group->property_x() = x;
canvas_group->property_y() = y;
@@ -104,10 +104,9 @@ StreamView::set_position (gdouble x, gdouble y)
}
int
-StreamView::set_height (gdouble h)
+StreamView::set_height (double h)
{
/* limit the values to something sane-ish */
-
if (h < 10.0 || h > 1000.0) {
return -1;
}
@@ -116,17 +115,8 @@ StreamView::set_height (gdouble h)
return 0;
}
- canvas_rect->property_y2() = h;
-
- for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
- (*i)->set_height (h);
- }
-
- for (vector<RecBoxInfo>::iterator i = rec_rects.begin(); i != rec_rects.end(); ++i) {
- RecBoxInfo &recbox = (*i);
- recbox.rectangle->property_y2() = h - 1.0;
- }
-
+ height = h;
+ update_contents_y_position_and_height ();
return 0;
}
@@ -162,6 +152,7 @@ void
StreamView::add_region_view (boost::shared_ptr<Region> r)
{
add_region_view_internal (r, true);
+ update_contents_y_position_and_height ();
}
void
@@ -203,9 +194,25 @@ StreamView::display_diskstream (boost::shared_ptr<Diskstream> ds)
}
void
-StreamView::playlist_modified ()
+StreamView::playlist_modified_weak (boost::weak_ptr<Diskstream> ds)
{
- ENSURE_GUI_THREAD (mem_fun (*this, &StreamView::playlist_modified));
+ boost::shared_ptr<Diskstream> sp (ds.lock());
+ if (!sp) {
+ return;
+ }
+
+ playlist_modified (sp);
+}
+
+void
+StreamView::playlist_modified (boost::shared_ptr<Diskstream> ds)
+{
+ /* we do not allow shared_ptr<T> to be bound to slots */
+ ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::playlist_modified_weak), ds));
+
+ /* update layers count and the y positions and heights of our regions */
+ layers = ds->playlist()->top_layer() + 1;
+ update_contents_y_position_and_height ();
redisplay_diskstream ();
}
@@ -213,6 +220,7 @@ StreamView::playlist_modified ()
void
StreamView::playlist_changed (boost::shared_ptr<Diskstream> ds)
{
+ /* XXX: binding to a shared_ptr, is this ok? */
ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::playlist_changed), ds));
/* disconnect from old playlist */
@@ -230,7 +238,11 @@ StreamView::playlist_changed (boost::shared_ptr<Diskstream> ds)
/* catch changes */
- playlist_connections.push_back (ds->playlist()->Modified.connect (mem_fun (*this, &StreamView::playlist_modified)));
+ playlist_connections.push_back (ds->playlist()->Modified.connect (bind (mem_fun (*this, &StreamView::playlist_modified_weak), ds)));
+
+ /* update layers count and the y positions and heights of our regions */
+ layers = ds->playlist()->top_layer() + 1;
+ update_contents_y_position_and_height ();
}
void
@@ -390,3 +402,33 @@ StreamView::get_inverted_selectables (Selection& sel, list<Selectable*>& results
}
}
+void
+StreamView::update_contents_y_position_and_height ()
+{
+ canvas_rect->property_y2() = height;
+
+ const double lh = height / layers;
+
+ for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
+ switch (layer_display) {
+ case Overlaid:
+ (*i)->set_y_position_and_height (0, height);
+ break;
+ case Stacked:
+ double const y = (*i)->region()->layer() * lh;
+ (*i)->set_y_position_and_height (y, lh);
+ break;
+ }
+ }
+
+ for (vector<RecBoxInfo>::iterator i = rec_rects.begin(); i != rec_rects.end(); ++i) {
+ i->rectangle->property_y2() = height - 1.0;
+ }
+}
+
+void
+StreamView::set_layer_display (LayerDisplay d)
+{
+ layer_display = d;
+ update_contents_y_position_and_height ();
+}
diff --git a/gtk2_ardour/streamview.h b/gtk2_ardour/streamview.h
index 39c04aea7f..365f2d4edf 100644
--- a/gtk2_ardour/streamview.h
+++ b/gtk2_ardour/streamview.h
@@ -68,11 +68,13 @@ public:
void set_zoom_all();
int set_position (gdouble x, gdouble y);
- virtual int set_height (gdouble);
+ virtual int set_height (double);
virtual int set_samples_per_unit (gdouble spp);
gdouble get_samples_per_unit () { return _samples_per_unit; }
+ void set_layer_display (LayerDisplay);
+
ArdourCanvas::Item* canvas_item() { return canvas_group; }
enum ColorTarget {
@@ -117,10 +119,12 @@ protected:
void diskstream_changed ();
virtual void playlist_changed (boost::shared_ptr<ARDOUR::Diskstream>);
- virtual void playlist_modified ();
+ virtual void playlist_modified_weak (boost::weak_ptr<ARDOUR::Diskstream>);
+ virtual void playlist_modified (boost::shared_ptr<ARDOUR::Diskstream>);
virtual void color_handler (ColorID, uint32_t) = 0;
+ virtual void update_contents_y_position_and_height ();
RouteTimeAxisView& _trackview;
ArdourCanvas::Group* canvas_group;
@@ -143,6 +147,10 @@ protected:
vector<sigc::connection> playlist_connections;
sigc::connection playlist_change_connection;
+
+ int layers;
+ double height;
+ LayerDisplay layer_display;
list<sigc::connection> rec_data_ready_connections;
jack_nframes_t last_rec_data_frame;
diff --git a/gtk2_ardour/time_axis_view_item.cc b/gtk2_ardour/time_axis_view_item.cc
index 7830e8f437..0e66ab2bae 100644
--- a/gtk2_ardour/time_axis_view_item.cc
+++ b/gtk2_ardour/time_axis_view_item.cc
@@ -567,15 +567,16 @@ TimeAxisViewItem::set_name_text(const ustring& new_name)
}
/**
- * Set the height of this item
+ * Set the y position and height of this item.
*
+ * @param y the new y position
* @param h the new height
*/
void
-TimeAxisViewItem::set_height (double height)
+TimeAxisViewItem::set_y_position_and_height (double y, double h)
{
if (name_highlight) {
- if (height < NAME_HIGHLIGHT_THRESH) {
+ if (h < NAME_HIGHLIGHT_THRESH) {
name_highlight->hide();
if (name_text) {
name_text->hide();
@@ -587,20 +588,20 @@ TimeAxisViewItem::set_height (double height)
}
}
- if (height > NAME_HIGHLIGHT_SIZE) {
- name_highlight->property_y1() = (double) height+1 - NAME_HIGHLIGHT_SIZE;
- name_highlight->property_y2() = (double) height;
+ if (h > NAME_HIGHLIGHT_SIZE) {
+ name_highlight->property_y1() = (double) y + h + 1 - NAME_HIGHLIGHT_SIZE;
+ name_highlight->property_y2() = (double) y + h;
}
else {
/* it gets hidden now anyway */
- name_highlight->property_y1() = (double) 1.0;
- name_highlight->property_y2() = (double) height;
+ name_highlight->property_y1() = (double) y;
+ name_highlight->property_y2() = (double) y + h;
}
}
if (name_text) {
- name_text->property_y() = height+1 - NAME_Y_OFFSET;
- if (height < NAME_HIGHLIGHT_THRESH) {
+ name_text->property_y() = y + h + 1 - NAME_Y_OFFSET;
+ if (h < NAME_HIGHLIGHT_THRESH) {
name_text->property_fill_color_rgba() = fill_color;
}
else {
@@ -609,10 +610,12 @@ TimeAxisViewItem::set_height (double height)
}
if (frame) {
- frame->property_y2() = height+1;
+ frame->property_y1() = y;
+ frame->property_y2() = y + h + 1;
}
- vestigial_frame->property_y2() = height+1;
+ vestigial_frame->property_y1() = y;
+ vestigial_frame->property_y2() = y + h + 1;
}
/**
diff --git a/gtk2_ardour/time_axis_view_item.h b/gtk2_ardour/time_axis_view_item.h
index aeeebe1c79..118a042920 100644
--- a/gtk2_ardour/time_axis_view_item.h
+++ b/gtk2_ardour/time_axis_view_item.h
@@ -201,12 +201,7 @@ class TimeAxisViewItem : public Selectable
*/
void set_name_text(const Glib::ustring& new_name) ;
- /**
- * Set the height of this item
- *
- * @param h the new height
- */
- virtual void set_height(double h) ;
+ virtual void set_y_position_and_height(double y, double h);
/**
*