summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2013-04-24 15:42:14 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2013-04-24 15:42:14 -0400
commit6f664c1f67f9a62d44b3ee8c3cae8c341e0731d3 (patch)
tree88133cd525135ef198b7bf9c4a7f1081826a5ac5
parentb36e085001cabc13f20f6b6779d08d9816d76b00 (diff)
many pervasive changes primarily related to waveform drawing, particular content-dragging, colors, and more
-rw-r--r--gtk2_ardour/audio_region_view.cc121
-rw-r--r--gtk2_ardour/audio_region_view.h1
-rw-r--r--gtk2_ardour/crossfade_edit.cc4
-rw-r--r--gtk2_ardour/editor.cc2
-rw-r--r--gtk2_ardour/editor_drag.cc25
-rw-r--r--gtk2_ardour/editor_tempodisplay.cc3
-rw-r--r--gtk2_ardour/ghostregion.cc5
-rw-r--r--gtk2_ardour/region_view.cc26
-rw-r--r--gtk2_ardour/region_view.h2
-rw-r--r--gtk2_ardour/streamview.cc4
-rw-r--r--gtk2_ardour/tempo_lines.cc10
-rw-r--r--gtk2_ardour/time_axis_view.cc4
-rw-r--r--gtk2_ardour/time_axis_view_item.cc38
-rw-r--r--gtk2_ardour/time_axis_view_item.h3
-rw-r--r--gtk2_ardour/verbose_cursor.cc5
-rw-r--r--libs/ardour/ardour/region.h2
-rw-r--r--libs/ardour/region.cc18
-rw-r--r--libs/canvas/canvas.cc85
-rw-r--r--libs/canvas/canvas/wave_view.h32
-rw-r--r--libs/canvas/group.cc8
-rw-r--r--libs/canvas/outline.cc36
-rw-r--r--libs/canvas/wave_view.cc229
22 files changed, 389 insertions, 274 deletions
diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc
index 68bd462eb5..7a509cd1d8 100644
--- a/gtk2_ardour/audio_region_view.cc
+++ b/gtk2_ardour/audio_region_view.cc
@@ -42,6 +42,7 @@
#include "canvas/poly_line.h"
#include "canvas/line.h"
#include "canvas/text.h"
+#include "canvas/debug.h"
#include "streamview.h"
#include "audio_region_view.h"
@@ -158,21 +159,25 @@ AudioRegionView::init (Gdk::Color const & basic_color, bool wfd)
create_waves ();
fade_in_shape = new ArdourCanvas::Polygon (group);
+ CANVAS_DEBUG_NAME (fade_in_shape, string_compose ("fade in shape for %1", region()->name()));
fade_in_shape->set_fill_color (fade_color);
fade_in_shape->set_data ("regionview", this);
fade_out_shape = new ArdourCanvas::Polygon (group);
+ CANVAS_DEBUG_NAME (fade_out_shape, string_compose ("fade out shape for %1", region()->name()));
fade_out_shape->set_fill_color (fade_color);
fade_out_shape->set_data ("regionview", this);
if (!_recregion) {
fade_in_handle = new ArdourCanvas::Rectangle (group);
+ CANVAS_DEBUG_NAME (fade_in_handle, string_compose ("fade in handle for %1", region()->name()));
fade_in_handle->set_fill_color (UINT_RGBA_CHANGE_A (fill_color, 0));
fade_in_handle->set_outline_color (RGBA_TO_UINT (0, 0, 0, 0));
fade_in_handle->set_data ("regionview", this);
fade_out_handle = new ArdourCanvas::Rectangle (group);
+ CANVAS_DEBUG_NAME (fade_out_handle, string_compose ("fade out handle for %1", region()->name()));
fade_out_handle->set_fill_color (UINT_RGBA_CHANGE_A (fill_color, 0));
fade_out_handle->set_outline_color (RGBA_TO_UINT (0, 0, 0, 0));
@@ -229,6 +234,9 @@ AudioRegionView::init (Gdk::Color const & basic_color, bool wfd)
setup_waveform_shape ();
setup_waveform_scale ();
+ frame_handle_start->raise_to_top ();
+ frame_handle_end->raise_to_top ();
+
/* XXX sync mark drag? */
}
@@ -360,10 +368,9 @@ AudioRegionView::region_resized (const PropertyChange& what_changed)
interesting_stuff.add (ARDOUR::Properties::length);
if (what_changed.contains (interesting_stuff)) {
-
+
for (uint32_t n = 0; n < waves.size(); ++n) {
waves[n]->region_resized ();
- waves[n]->set_region_start (region()->start ());
}
for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
@@ -371,7 +378,6 @@ AudioRegionView::region_resized (const PropertyChange& what_changed)
for (vector<WaveView*>::iterator w = agr->waves.begin(); w != agr->waves.end(); ++w) {
(*w)->region_resized ();
- (*w)->set_region_start (region()->start ());
}
}
}
@@ -432,14 +438,7 @@ void
AudioRegionView::region_muted ()
{
RegionView::region_muted();
-
- for (uint32_t n=0; n < waves.size(); ++n) {
- if (_region->muted()) {
- waves[n]->set_outline_color (UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->get_canvasvar_WaveForm(), MUTED_ALPHA));
- } else {
- waves[n]->set_outline_color (ARDOUR_UI::config()->get_canvasvar_WaveForm());
- }
- }
+ set_waveform_colors ();
}
void
@@ -750,12 +749,14 @@ AudioRegionView::redraw_start_xfade_to (boost::shared_ptr<AudioRegion> ar, frame
if (!start_xfade_in) {
start_xfade_in = new ArdourCanvas::PolyLine (group);
+ CANVAS_DEBUG_NAME (start_xfade_in, string_compose ("xfade start in line for %1", region()->name()));
start_xfade_in->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeLine());
start_xfade_in->set_outline_width (1.5);
}
if (!start_xfade_out) {
start_xfade_out = new ArdourCanvas::PolyLine (group);
+ CANVAS_DEBUG_NAME (start_xfade_out, string_compose ("xfade start out line for %1", region()->name()));
uint32_t col = UINT_RGBA_CHANGE_A (ARDOUR_UI::config()->get_canvasvar_CrossfadeLine(), 128);
start_xfade_out->set_outline_color (col);
start_xfade_out->set_outline_width (2.0);
@@ -763,6 +764,7 @@ AudioRegionView::redraw_start_xfade_to (boost::shared_ptr<AudioRegion> ar, frame
if (!start_xfade_rect) {
start_xfade_rect = new ArdourCanvas::Rectangle (group);
+ CANVAS_DEBUG_NAME (start_xfade_rect, string_compose ("xfade start rect for %1", region()->name()));
start_xfade_rect->set_fill (true);
start_xfade_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_ActiveCrossfade());
start_xfade_rect->set_outline (false);
@@ -775,7 +777,6 @@ AudioRegionView::redraw_start_xfade_to (boost::shared_ptr<AudioRegion> ar, frame
start_xfade_in->set (points);
start_xfade_in->show ();
- start_xfade_in->raise_to_top ();
/* fade out line */
@@ -807,9 +808,6 @@ AudioRegionView::redraw_start_xfade_to (boost::shared_ptr<AudioRegion> ar, frame
start_xfade_out->set (ipoints);
start_xfade_out->show ();
- start_xfade_out->raise_to_top ();
-
- start_xfade_rect->raise_to_top (); //this needs to be topmost so the lines don't steal mouse focus
show_start_xfade();
}
@@ -837,6 +835,7 @@ AudioRegionView::redraw_end_xfade_to (boost::shared_ptr<AudioRegion> ar, framecn
if (!end_xfade_in) {
end_xfade_in = new ArdourCanvas::PolyLine (group);
+ CANVAS_DEBUG_NAME (end_xfade_in, string_compose ("xfade end in line for %1", region()->name()));
uint32_t col UINT_RGBA_CHANGE_A (ARDOUR_UI::config()->get_canvasvar_CrossfadeLine(), 128);
end_xfade_in->set_outline_color (col);
end_xfade_in->set_outline_width (1.5);
@@ -844,12 +843,14 @@ AudioRegionView::redraw_end_xfade_to (boost::shared_ptr<AudioRegion> ar, framecn
if (!end_xfade_out) {
end_xfade_out = new ArdourCanvas::PolyLine (group);
+ CANVAS_DEBUG_NAME (end_xfade_out, string_compose ("xfade end out line for %1", region()->name()));
end_xfade_out->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeLine());
end_xfade_out->set_outline_width (2.0);
}
if (!end_xfade_rect) {
end_xfade_rect = new ArdourCanvas::Rectangle (group);
+ CANVAS_DEBUG_NAME (end_xfade_rect, string_compose ("xfade end rect for %1", region()->name()));
end_xfade_rect->set_fill (true);
end_xfade_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_ActiveCrossfade());
end_xfade_rect->set_outline (0);
@@ -1025,16 +1026,7 @@ AudioRegionView::set_colors ()
ARDOUR_UI::config()->get_canvasvar_GainLineInactive());
}
- for (uint32_t n=0; n < waves.size(); ++n) {
- if (_region->muted()) {
- waves[n]->set_outline_color (UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->get_canvasvar_WaveForm(), MUTED_ALPHA));
- } else {
- waves[n]->set_outline_color (ARDOUR_UI::config()->get_canvasvar_WaveForm());
- }
-
- waves[n]->set_clip_color (ARDOUR_UI::config()->get_canvasvar_WaveFormClip());
- waves[n]->set_zero_color (ARDOUR_UI::config()->get_canvasvar_ZeroLine());
- }
+ set_waveform_colors ();
if (start_xfade_in) {
start_xfade_in->set_outline_color (ARDOUR_UI::config()->get_canvasvar_CrossfadeLine());
@@ -1181,9 +1173,10 @@ AudioRegionView::create_one_wave (uint32_t which, bool /*direct*/)
gdouble yoff = which * ht;
WaveView *wave = new WaveView (group, audio_region ());
-
+ CANVAS_DEBUG_NAME (wave, string_compose ("wave view for chn %1 of %2", which, get_item_name()));
+
+ wave->lower_to_bottom ();
wave->set_channel (which);
- wave->set_x_position (0);
wave->set_y_position (yoff);
wave->set_height (ht);
wave->set_samples_per_pixel (samples_per_pixel);
@@ -1201,8 +1194,6 @@ AudioRegionView::create_one_wave (uint32_t which, bool /*direct*/)
// CAIROCANVAS
// wave->property_zero_line() = true;
- wave->set_region_start (_region->start());
-
switch (Config->get_waveform_shape()) {
case Rectified:
wave->set_shape (WaveView::Rectified);
@@ -1362,12 +1353,11 @@ AudioRegionView::add_ghost (TimeAxisView& tv)
}
WaveView *wave = new WaveView (ghost->group, audio_region());
+ CANVAS_DEBUG_NAME (wave, string_compose ("ghost wave for %1", get_item_name()));
wave->set_channel (n);
- wave->set_x_position (0);
wave->set_samples_per_pixel (samples_per_pixel);
wave->set_amplitude_above_axis (_amplitude_above_axis);
- wave->set_region_start (_region->start());
ghost->waves.push_back(wave);
}
@@ -1442,54 +1432,62 @@ AudioRegionView::color_handler ()
}
void
-AudioRegionView::set_frame_color ()
+AudioRegionView::set_waveform_colors ()
{
- if (!frame) {
- return;
- }
-
- if (_region->opaque()) {
- fill_opacity = 130;
- } else {
- fill_opacity = 0;
- }
-
- TimeAxisViewItem::set_frame_color ();
-
- uint32_t wc;
- uint32_t fc;
-
+ ArdourCanvas::Color fill, outline, clip, zero;
+
if (_selected) {
if (_region->muted()) {
- wc = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->get_canvasvar_SelectedWaveForm(), MUTED_ALPHA);
+ outline = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->get_canvasvar_SelectedWaveForm(), MUTED_ALPHA);
} else {
- wc = ARDOUR_UI::config()->get_canvasvar_SelectedWaveForm();
+ outline = ARDOUR_UI::config()->get_canvasvar_SelectedWaveForm();
}
- fc = ARDOUR_UI::config()->get_canvasvar_SelectedWaveFormFill();
+ fill = ARDOUR_UI::config()->get_canvasvar_SelectedWaveFormFill();
} else {
if (_recregion) {
if (_region->muted()) {
- wc = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->get_canvasvar_RecWaveForm(), MUTED_ALPHA);
+ outline = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->get_canvasvar_RecWaveForm(), MUTED_ALPHA);
} else {
- wc = ARDOUR_UI::config()->get_canvasvar_RecWaveForm();
+ outline = ARDOUR_UI::config()->get_canvasvar_RecWaveForm();
}
- fc = ARDOUR_UI::config()->get_canvasvar_RecWaveFormFill();
+ fill = ARDOUR_UI::config()->get_canvasvar_RecWaveFormFill();
} else {
if (_region->muted()) {
- wc = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->get_canvasvar_WaveForm(), MUTED_ALPHA);
+ outline = UINT_RGBA_CHANGE_A(ARDOUR_UI::config()->get_canvasvar_WaveForm(), MUTED_ALPHA);
} else {
- wc = ARDOUR_UI::config()->get_canvasvar_WaveForm();
+ outline = ARDOUR_UI::config()->get_canvasvar_WaveForm();
}
- fc = ARDOUR_UI::config()->get_canvasvar_WaveFormFill();
+ fill = ARDOUR_UI::config()->get_canvasvar_WaveFormFill();
}
}
+ clip = ARDOUR_UI::config()->get_canvasvar_WaveFormClip();
+ zero = ARDOUR_UI::config()->get_canvasvar_ZeroLine();
+
for (vector<ArdourCanvas::WaveView*>::iterator w = waves.begin(); w != waves.end(); ++w) {
- (*w)->set_outline_color (wc);
- if (!_region->muted()) {
- (*w)->set_fill_color (fc);
- }
- }
+ (*w)->set_outline_color (outline);
+ (*w)->set_fill_color (fill);
+ (*w)->set_clip_color (clip);
+ (*w)->set_zero_color (zero);
+ }
+}
+
+void
+AudioRegionView::set_frame_color ()
+{
+ if (!frame) {
+ return;
+ }
+
+ if (_region->opaque()) {
+ fill_opacity = 130;
+ } else {
+ fill_opacity = 0;
+ }
+
+ TimeAxisViewItem::set_frame_color ();
+
+ set_waveform_colors ();
}
void
@@ -1555,6 +1553,7 @@ AudioRegionView::transients_changed ()
while (feature_lines.size() < analysis_features.size()) {
ArdourCanvas::Line* canvas_item = new ArdourCanvas::Line(group);
+ CANVAS_DEBUG_NAME (canvas_item, string_compose ("transient group for %1", region()->name()));
canvas_item->set (ArdourCanvas::Duple (-1.0, 2.0),
ArdourCanvas::Duple (1.0, _height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 1));
diff --git a/gtk2_ardour/audio_region_view.h b/gtk2_ardour/audio_region_view.h
index 719dfc2b55..049b61a571 100644
--- a/gtk2_ardour/audio_region_view.h
+++ b/gtk2_ardour/audio_region_view.h
@@ -189,6 +189,7 @@ class AudioRegionView : public RegionView
void peaks_ready_handler (uint32_t);
void set_colors ();
+ void set_waveform_colors ();
void compute_colors (Gdk::Color const &);
void reset_width_dependent_items (double pixel_width);
void set_frame_color ();
diff --git a/gtk2_ardour/crossfade_edit.cc b/gtk2_ardour/crossfade_edit.cc
index 5d6e0d465d..214ba7fb06 100644
--- a/gtk2_ardour/crossfade_edit.cc
+++ b/gtk2_ardour/crossfade_edit.cc
@@ -1172,9 +1172,7 @@ CrossfadeEditor::make_waves (boost::shared_ptr<AudioRegion> region, WhichFade wh
waveview->set_outline_color (color);
waveview->set_fill_color (color);
- if (which == In) {
- waveview->set_region_start (region->start());
- } else {
+ if (which != In) {
waveview->set_region_start (region->start() + region->length() - xfade->length());
}
diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc
index d458b41b84..3f06a5b87b 100644
--- a/gtk2_ardour/editor.cc
+++ b/gtk2_ardour/editor.cc
@@ -3731,7 +3731,7 @@ Editor::set_show_measures (bool yn)
compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
draw_measures (begin, end);
- }
+ }
instant_save ();
}
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc
index 35a7e930ef..3dbb48ce43 100644
--- a/gtk2_ardour/editor_drag.cc
+++ b/gtk2_ardour/editor_drag.cc
@@ -1830,6 +1830,7 @@ TrimDrag::motion (GdkEvent* event, bool first_move)
TimeAxisView* tvp = &_primary->get_time_axis_view ();
RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
+ frameoffset_t frame_delta = 0;
if (tv && tv->is_track()) {
speed = tv->track()->speed();
@@ -1926,27 +1927,11 @@ TrimDrag::motion (GdkEvent* event, bool first_move)
case ContentsTrim:
{
- bool swap_direction = false;
-
- if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
- swap_direction = true;
- }
-
- framecnt_t frame_delta = 0;
-
- bool left_direction = false;
- if (last_pointer_frame() > adjusted_current_frame(event)) {
- left_direction = true;
- }
-
- if (left_direction) {
- frame_delta = (last_pointer_frame() - adjusted_current_frame(event));
- } else {
- frame_delta = (adjusted_current_frame(event) - last_pointer_frame());
- }
+ frame_delta = (adjusted_current_frame(event) - last_pointer_frame());
+ // frame_delta = (last_pointer_frame() - adjusted_current_frame(event));
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- i->view->trim_contents (frame_delta, left_direction, swap_direction);
+ i->view->move_contents (frame_delta);
}
}
break;
@@ -1960,7 +1945,7 @@ TrimDrag::motion (GdkEvent* event, bool first_move)
show_verbose_cursor_time ((framepos_t) (rv->region()->last_frame() / speed));
break;
case ContentsTrim:
- show_verbose_cursor_time (adjusted_current_frame (event));
+ // show_verbose_cursor_time (frame_delta);
break;
}
}
diff --git a/gtk2_ardour/editor_tempodisplay.cc b/gtk2_ardour/editor_tempodisplay.cc
index 09d9b39c73..400f427ee5 100644
--- a/gtk2_ardour/editor_tempodisplay.cc
+++ b/gtk2_ardour/editor_tempodisplay.cc
@@ -162,8 +162,9 @@ Editor::compute_current_bbt_points (framepos_t leftmost, framepos_t rightmost,
void
Editor::hide_measures ()
{
- if (tempo_lines)
+ if (tempo_lines) {
tempo_lines->hide();
+ }
}
void
diff --git a/gtk2_ardour/ghostregion.cc b/gtk2_ardour/ghostregion.cc
index 6801e80d02..5350a0e459 100644
--- a/gtk2_ardour/ghostregion.cc
+++ b/gtk2_ardour/ghostregion.cc
@@ -21,6 +21,8 @@
#include "canvas/group.h"
#include "canvas/rectangle.h"
#include "canvas/wave_view.h"
+#include "canvas/debug.h"
+
#include "ardour_ui.h"
#include "automation_time_axis.h"
#include "ghostregion.h"
@@ -41,9 +43,11 @@ GhostRegion::GhostRegion (ArdourCanvas::Group* parent, TimeAxisView& tv, TimeAxi
, source_trackview (source_tv)
{
group = new ArdourCanvas::Group (parent);
+ CANVAS_DEBUG_NAME (group, "ghost region group");
group->set_position (ArdourCanvas::Duple (initial_pos, 0));
base_rect = new ArdourCanvas::Rectangle (group);
+ CANVAS_DEBUG_NAME (base_rect, "ghost region rect");
base_rect->set_x0 (0);
base_rect->set_y0 (0);
base_rect->set_y1 (trackview.current_height());
@@ -191,6 +195,7 @@ MidiGhostRegion::GhostEvent::GhostEvent (NoteBase* e, ArdourCanvas::Group* g)
: event (e)
{
rect = new ArdourCanvas::Rectangle (g, ArdourCanvas::Rect (e->x0(), e->y0(), e->x1(), e->y1()));
+ CANVAS_DEBUG_NAME (rect, "ghost note rect");
}
MidiGhostRegion::GhostEvent::~GhostEvent ()
diff --git a/gtk2_ardour/region_view.cc b/gtk2_ardour/region_view.cc
index 37ddb45917..ac7fe7e8fa 100644
--- a/gtk2_ardour/region_view.cc
+++ b/gtk2_ardour/region_view.cc
@@ -632,9 +632,11 @@ RegionView::region_sync_changed ()
/* points set below */
sync_mark = new ArdourCanvas::Polygon (group);
+ CANVAS_DEBUG_NAME (sync_mark, string_compose ("sync mark for %1", get_item_name()));
sync_mark->set_fill_color (RGBA_TO_UINT(0,255,0,255)); // FIXME make a themeable colour
sync_line = new ArdourCanvas::Line (group);
+ CANVAS_DEBUG_NAME (sync_line, string_compose ("sync mark for %1", get_item_name()));
sync_line->set_outline_color (RGBA_TO_UINT(0,255,0,255)); // FIXME make a themeable colour
}
@@ -930,32 +932,12 @@ RegionView::thaw_after_trim ()
void
-RegionView::trim_contents (framepos_t frame_delta, bool left_direction, bool swap_direction)
+RegionView::move_contents (frameoffset_t distance)
{
if (_region->locked()) {
return;
}
-
- framepos_t new_bound;
-
- RouteTimeAxisView& rtv = dynamic_cast<RouteTimeAxisView&> (trackview);
- double const speed = rtv.track()->speed ();
-
- if (left_direction) {
- if (swap_direction) {
- new_bound = (framepos_t) (_region->position() / speed) + frame_delta;
- } else {
- new_bound = (framepos_t) (_region->position() / speed) - frame_delta;
- }
- } else {
- if (swap_direction) {
- new_bound = (framepos_t) (_region->position() / speed) - frame_delta;
- } else {
- new_bound = (framepos_t) (_region->position() / speed) + frame_delta;
- }
- }
-
- _region->trim_start ((framepos_t) (new_bound * speed));
+ _region->move_start (distance);
region_changed (PropertyChange (ARDOUR::Properties::start));
}
diff --git a/gtk2_ardour/region_view.h b/gtk2_ardour/region_view.h
index 566304fa92..74d1f29581 100644
--- a/gtk2_ardour/region_view.h
+++ b/gtk2_ardour/region_view.h
@@ -113,7 +113,7 @@ class RegionView : public TimeAxisViewItem
virtual void trim_front_ending () {}
bool trim_end (framepos_t, bool);
- void trim_contents (framepos_t, bool, bool);
+ void move_contents (ARDOUR::frameoffset_t);
virtual void thaw_after_trim ();
void set_silent_frames (const ARDOUR::AudioIntervalResult&, double threshold);
diff --git a/gtk2_ardour/streamview.cc b/gtk2_ardour/streamview.cc
index 774e150f13..8239bca2f4 100644
--- a/gtk2_ardour/streamview.cc
+++ b/gtk2_ardour/streamview.cc
@@ -71,8 +71,10 @@ StreamView::StreamView (RouteTimeAxisView& tv)
canvas_rect->set (ArdourCanvas::Rect (0, 0, ArdourCanvas::COORD_MAX, tv.current_height ()));
canvas_rect->raise(1); // raise above tempo lines
- canvas_rect->set_outline_what (0x2 | 0x8);
+ canvas_rect->set_outline_what (ArdourCanvas::Rectangle::What (ArdourCanvas::Rectangle::TOP | ArdourCanvas::Rectangle::BOTTOM));
canvas_rect->set_outline_color (RGBA_TO_UINT (0, 0, 0, 255));
+ canvas_rect->set_fill_color (RGBA_TO_UINT (1.0, 0, 0, 255));
+ canvas_rect->set_fill (true);
canvas_rect->Event.connect (sigc::bind (
sigc::mem_fun (_trackview.editor(), &PublicEditor::canvas_stream_view_event),
diff --git a/gtk2_ardour/tempo_lines.cc b/gtk2_ardour/tempo_lines.cc
index a6177d2b1d..d73fb54b81 100644
--- a/gtk2_ardour/tempo_lines.cc
+++ b/gtk2_ardour/tempo_lines.cc
@@ -47,17 +47,13 @@ TempoLines::tempo_map_changed()
void
TempoLines::show ()
{
- for (Lines::iterator i = _lines.begin(); i != _lines.end(); ++i) {
- (*i)->show();
- }
+ _group->show ();
}
void
TempoLines::hide ()
{
- for (Lines::iterator i = _lines.begin(); i != _lines.end(); ++i) {
- (*i)->hide();
- }
+ _group->hide ();
}
void
@@ -111,6 +107,8 @@ TempoLines::draw (const ARDOUR::TempoMap::BBTPointList::const_iterator& begin,
line->reparent (_group);
} else {
line = new ArdourCanvas::Line (_group);
+ CANVAS_DEBUG_NAME (line, "tempo measure line");
+ line->set_ignore_events (true);
}
line->set_x0 (xpos);
diff --git a/gtk2_ardour/time_axis_view.cc b/gtk2_ardour/time_axis_view.cc
index cfa22ae805..280802ab68 100644
--- a/gtk2_ardour/time_axis_view.cc
+++ b/gtk2_ardour/time_axis_view.cc
@@ -32,6 +32,7 @@
#include <gtkmm2ext/selector.h>
#include "canvas/rectangle.h"
+#include "canvas/debug.h"
#include "ardour_ui.h"
#include "ardour_dialog.h"
@@ -940,13 +941,16 @@ TimeAxisView::get_selection_rect (uint32_t id)
rect = new SelectionRect;
rect->rect = new ArdourCanvas::Rectangle (selection_group);
+ CANVAS_DEBUG_NAME (rect->rect, "selection rect");
rect->rect->set_outline_what (0);
rect->rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_SelectionRect());
rect->start_trim = new ArdourCanvas::Rectangle (selection_group);
+ CANVAS_DEBUG_NAME (rect->rect, "selection rect start trim");
rect->start_trim->set_outline_what (0);
rect->end_trim = new ArdourCanvas::Rectangle (selection_group);
+ CANVAS_DEBUG_NAME (rect->rect, "selection rect end trim");
rect->end_trim->set_outline_what (0);
free_selection_rects.push_front (rect);
diff --git a/gtk2_ardour/time_axis_view_item.cc b/gtk2_ardour/time_axis_view_item.cc
index 57bda5fa26..4c2e31c22d 100644
--- a/gtk2_ardour/time_axis_view_item.cc
+++ b/gtk2_ardour/time_axis_view_item.cc
@@ -138,6 +138,7 @@ TimeAxisViewItem::TimeAxisViewItem (const TimeAxisViewItem& other)
ArdourCanvas::Group* parent = other.group->parent();
group = new ArdourCanvas::Group (parent);
+ CANVAS_DEBUG_NAME (group, string_compose ("TAVI group for %1", get_item_name()));
_selected = other._selected;
@@ -171,6 +172,7 @@ TimeAxisViewItem::init (const string& it_name, double fpp, Gdk::Color const & ba
}
vestigial_frame = new ArdourCanvas::Rectangle (group, ArdourCanvas::Rect (0.0, 1.0, 2.0, trackview.current_height()));
+ CANVAS_DEBUG_NAME (vestigial_frame, string_compose ("vestigial frame for %1", get_item_name()));
vestigial_frame->hide ();
vestigial_frame->set_outline_color (ARDOUR_UI::config()->get_canvasvar_VestigialFrame());
vestigial_frame->set_fill_color (ARDOUR_UI::config()->get_canvasvar_VestigialFrame());
@@ -180,6 +182,7 @@ TimeAxisViewItem::init (const string& it_name, double fpp, Gdk::Color const & ba
ArdourCanvas::Rect (0.0, 1.0,
trackview.editor().sample_to_pixel(duration),
trackview.current_height()));
+ CANVAS_DEBUG_NAME (frame, string_compose ("frame for %1", get_item_name()));
if (_recregion) {
frame->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RecordingRect());
@@ -199,11 +202,13 @@ TimeAxisViewItem::init (const string& it_name, double fpp, Gdk::Color const & ba
ArdourCanvas::Rect (0.0, trackview.editor().sample_to_pixel(item_duration),
trackview.current_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE,
trackview.current_height()));
+ CANVAS_DEBUG_NAME (name_highlight, string_compose ("name highlight for %1", get_item_name()));
} else {
name_highlight = new ArdourCanvas::Rectangle (group,
ArdourCanvas::Rect (1.0, trackview.editor().sample_to_pixel(item_duration) - 1,
trackview.current_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE,
trackview.current_height()));
+ CANVAS_DEBUG_NAME (name_highlight, string_compose ("name highlight for %1", get_item_name()));
}
name_highlight->set_data ("timeaxisviewitem", this);
@@ -217,6 +222,7 @@ TimeAxisViewItem::init (const string& it_name, double fpp, Gdk::Color const & ba
if (visibility & ShowNameText) {
name_text = new ArdourCanvas::Text (group);
+ CANVAS_DEBUG_NAME (name_text, string_compose ("name text for %1", get_item_name()));
name_text->set_position (ArdourCanvas::Duple (NAME_X_OFFSET, trackview.current_height() - NAME_Y_OFFSET));
name_text->set_font_description (NAME_FONT);
@@ -230,9 +236,16 @@ TimeAxisViewItem::init (const string& it_name, double fpp, Gdk::Color const & ba
double width = TimeAxisViewItem::GRAB_HANDLE_WIDTH;
frame_handle_start = new ArdourCanvas::Rectangle (group, ArdourCanvas::Rect (0.0, top, width, trackview.current_height()));
- frame_handle_start->set_outline_what (ArdourCanvas::Rectangle::What (0));
+ CANVAS_DEBUG_NAME (frame_handle_start, "TAVI frame handle start");
+ frame_handle_start->set_outline (false);
+ frame_handle_start->set_fill (false);
+ frame_handle_start->Event.connect (sigc::bind (sigc::mem_fun (*this, &TimeAxisViewItem::frame_handle_crossing), frame_handle_start));
+
frame_handle_end = new ArdourCanvas::Rectangle (group, ArdourCanvas::Rect (0.0, top, width, trackview.current_height()));
- frame_handle_end->set_outline_what (ArdourCanvas::Rectangle::What (0));
+ CANVAS_DEBUG_NAME (frame_handle_end, "TAVI frame handle end");
+ frame_handle_end->set_outline (false);
+ frame_handle_end->set_fill (false);
+ frame_handle_end->Event.connect (sigc::bind (sigc::mem_fun (*this, &TimeAxisViewItem::frame_handle_crossing), frame_handle_end));
} else {
frame_handle_start = frame_handle_end = 0;
}
@@ -819,12 +832,28 @@ TimeAxisViewItem::set_trim_handle_colors()
frame_handle_start->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TrimHandleLocked());
frame_handle_end->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TrimHandleLocked());
} else {
- frame_handle_start->set_fill_color (RGBA_TO_UINT (1, 1, 1, 0)); //ARDOUR_UI::config()->get_canvasvar_TrimHandle();
- frame_handle_end->set_fill_color (RGBA_TO_UINT (1, 1, 1, 0)); //ARDOUR_UI::config()->get_canvasvar_TrimHandle();
+ frame_handle_start->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TrimHandle());
+ frame_handle_end->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TrimHandle());
}
}
}
+bool
+TimeAxisViewItem::frame_handle_crossing (GdkEvent* ev, ArdourCanvas::Rectangle* item)
+{
+ switch (ev->type) {
+ case GDK_LEAVE_NOTIFY:
+ item->set_fill (false);
+ break;
+ case GDK_ENTER_NOTIFY:
+ item->set_fill (true);
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
/** @return the frames per pixel */
double
TimeAxisViewItem::get_samples_per_pixel () const
@@ -901,6 +930,7 @@ TimeAxisViewItem::reset_width_dependent_items (double pixel_width)
* the right-hand end of frame_handle_start and the left-hand
* end of frame_handle_end, so disable the handles
*/
+
frame_handle_start->hide();
frame_handle_end->hide();
} else {
diff --git a/gtk2_ardour/time_axis_view_item.h b/gtk2_ardour/time_axis_view_item.h
index f6f72b77bd..08cc421202 100644
--- a/gtk2_ardour/time_axis_view_item.h
+++ b/gtk2_ardour/time_axis_view_item.h
@@ -21,6 +21,7 @@
#define __gtk_ardour_time_axis_view_item_h__
#include <string>
+#include <gdk/gdk.h>
#include <gdkmm/color.h>
#include <pangomm/fontdescription.h>
#include "pbd/signals.h"
@@ -244,6 +245,8 @@ class TimeAxisViewItem : public Selectable, public PBD::ScopedConnectionList
ArdourCanvas::Rectangle* frame_handle_start; ///< `frame' (fade) handle for the start of the item, or 0
ArdourCanvas::Rectangle* frame_handle_end; ///< `frame' (fade) handle for the end of the item, or 0
+ bool frame_handle_crossing (GdkEvent*, ArdourCanvas::Rectangle*);
+
double _height;
Visibility visibility;
bool _recregion;
diff --git a/gtk2_ardour/verbose_cursor.cc b/gtk2_ardour/verbose_cursor.cc
index 1f43f754e6..fec9e80ae1 100644
--- a/gtk2_ardour/verbose_cursor.cc
+++ b/gtk2_ardour/verbose_cursor.cc
@@ -22,6 +22,8 @@
#include "pbd/stacktrace.h"
#include "ardour/profile.h"
+#include "canvas/debug.h"
+
#include "ardour_ui.h"
#include "audio_clock.h"
#include "editor.h"
@@ -42,10 +44,9 @@ VerboseCursor::VerboseCursor (Editor* editor)
, _yoffset (0)
{
_canvas_item = new ArdourCanvas::Text (_editor->_track_canvas->root());
+ CANVAS_DEBUG_NAME (_canvas_item, "verbose canvas cursor");
_canvas_item->set_ignore_events (true);
_canvas_item->set_font_description (get_font_for_style (N_("VerboseCanvasCursor")));
- // CAIROCANVAS
- // _canvas_item->property_anchor() = Gtk::ANCHOR_NW;
}
ArdourCanvas::Item *
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index 3ee829ed12..593832343f 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -220,7 +220,7 @@ class Region
bool at_natural_position () const;
void move_to_natural_position ();
- void trim_start (framepos_t new_position);
+ void move_start (frameoffset_t distance);
void trim_front (framepos_t new_position);
void trim_end (framepos_t new_position);
void trim_to (framepos_t position, framecnt_t length);
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index 706dda4a0a..847a72b23f 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -698,33 +698,32 @@ Region::set_start (framepos_t pos)
}
void
-Region::trim_start (framepos_t new_position)
+Region::move_start (frameoffset_t distance)
{
if (locked() || position_locked() || video_locked()) {
return;
}
framepos_t new_start;
- frameoffset_t const start_shift = new_position - _position;
- if (start_shift > 0) {
+ if (distance > 0) {
- if (_start > max_framepos - start_shift) {
- new_start = max_framepos;
+ if (_start > max_framepos - distance) {
+ new_start = max_framepos; // makes no sense
} else {
- new_start = _start + start_shift;
+ new_start = _start + distance;
}
if (!verify_start (new_start)) {
return;
}
- } else if (start_shift < 0) {
+ } else if (distance < 0) {
- if (_start < -start_shift) {
+ if (_start < -distance) {
new_start = 0;
} else {
- new_start = _start + start_shift;
+ new_start = _start + distance;
}
} else {
@@ -736,6 +735,7 @@ Region::trim_start (framepos_t new_position)
}
set_start_internal (new_start);
+
_whole_file = false;
first_edit ();
diff --git a/libs/canvas/canvas.cc b/libs/canvas/canvas.cc
index 9707f2304d..48bfbaaf4d 100644
--- a/libs/canvas/canvas.cc
+++ b/libs/canvas/canvas.cc
@@ -61,9 +61,10 @@ Canvas::render (Rect const & area, Cairo::RefPtr<Cairo::Context> const & context
{
#ifdef CANVAS_DEBUG
if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
- cerr << "CANVAS @ " << this << endl;
- dump (cerr);
- cerr << "-------------------------\n";
+ cerr << "RENDER: " << area << endl;
+ //cerr << "CANVAS @ " << this << endl;
+ //dump (cerr);
+ //cerr << "-------------------------\n";
}
#endif
@@ -78,9 +79,9 @@ Canvas::render (Rect const & area, Cairo::RefPtr<Cairo::Context> const & context
context->set_source_rgba (random()%255 / 255.0,
random()%255 / 255.0,
random()%255 / 255.0,
- 255);
+ 0.3);
context->rectangle (area.x0, area.y0, area.width(), area.height());
- context->stroke ();
+ context->fill ();
}
#endif
@@ -119,7 +120,7 @@ Canvas::render (Rect const & area, Cairo::RefPtr<Cairo::Context> const & context
context->set_source_rgba (random()%255 / 255.0,
random()%255 / 255.0,
random()%255 / 255.0,
- 255);
+ 0.4);
context->rectangle (area.x0, area.y0, area.width(), area.height());
context->fill ();
}
@@ -327,6 +328,11 @@ GtkCanvas::enter_leave_items ()
{
int x;
int y;
+
+ /* this version of ::enter_leave_items() is called after an item is
+ * added or removed, so we have no coordinates to work from as is the
+ * case with a motion event. Find out where the mouse is and use that.
+ */
Glib::RefPtr<const Gdk::Window> pointer_window = Gdk::Display::get_default()->get_window_at_pointer (x, y);
@@ -340,31 +346,60 @@ GtkCanvas::enter_leave_items ()
void
GtkCanvas::enter_leave_items (Duple const & point)
{
- /* find the items at the new mouse position */
+ /* find the items at the given position */
+
vector<Item const *> items;
_root.add_items_at_point (point, items);
- Item const * new_item = items.empty() ? 0 : items.back ();
-
- if (_current_item && _current_item != new_item) {
- /* leave event */
- GdkEventCrossing leave_event;
- leave_event.type = GDK_LEAVE_NOTIFY;
- leave_event.x = point.x;
- leave_event.y = point.y;
- _current_item->Event (reinterpret_cast<GdkEvent*> (&leave_event));
+ if (items.empty()) {
+ if (_current_item) {
+ /* leave event */
+ GdkEventCrossing leave_event;
+ leave_event.type = GDK_LEAVE_NOTIFY;
+ leave_event.x = point.x;
+ leave_event.y = point.y;
+ cerr << "Leaving (without entering)" << _current_item->name << endl;
+ _current_item->Event (reinterpret_cast<GdkEvent*> (&leave_event));
+ _current_item = 0;
+ }
+ return;
}
- if (new_item && _current_item != new_item) {
- /* enter event */
- GdkEventCrossing enter_event;
- enter_event.type = GDK_ENTER_NOTIFY;
- enter_event.x = point.x;
- enter_event.y = point.y;
- new_item->Event (reinterpret_cast<GdkEvent*> (&enter_event));
- }
+ /* items is sorted from bottom to top, so reverse through it from top
+ * to bottom to find the first event-sensitive item and notify that
+ * we have entered it
+ */
- _current_item = new_item;
+ for (vector<Item const*>::const_reverse_iterator i = items.rbegin(); i != items.rend(); ++i) {
+
+ Item const * new_item = *i;
+
+ if (new_item->ignore_events()) {
+ continue;
+ }
+ if (_current_item && _current_item != new_item) {
+ /* leave event */
+ GdkEventCrossing leave_event;
+ leave_event.type = GDK_LEAVE_NOTIFY;
+ leave_event.x = point.x;
+ leave_event.y = point.y;
+ cerr << "Leaving " << _current_item->name << endl;
+ _current_item->Event (reinterpret_cast<GdkEvent*> (&leave_event));
+ }
+
+ if (new_item && _current_item != new_item) {
+ /* enter event */
+ GdkEventCrossing enter_event;
+ enter_event.type = GDK_ENTER_NOTIFY;
+ enter_event.x = point.x;
+ enter_event.y = point.y;
+ cerr << "Entering (" << new_item->name << ") " << new_item->whatami() << endl;
+ new_item->Event (reinterpret_cast<GdkEvent*> (&enter_event));
+ }
+
+ _current_item = new_item;
+ break;
+ }
}
/** Deliver an event to the appropriate item; either the grabbed item, or
diff --git a/libs/canvas/canvas/wave_view.h b/libs/canvas/canvas/wave_view.h
index f88ca41ba4..b75b8c5312 100644
--- a/libs/canvas/canvas/wave_view.h
+++ b/libs/canvas/canvas/wave_view.h
@@ -105,17 +105,31 @@ private:
#endif
+ /** A cached, pre-rendered image of some section of a waveform.
+
+ It spans a range given relative to the start of the source
+ of the waveform data, so a range from N..M corresponds
+ to the sample range N..M within the source.
+
+ Invalidated by a changes to:
+
+ samples_per_pixel
+ colors
+ height
+
+ */
+
class CacheEntry
{
- public:
- CacheEntry (WaveView const *, int, int);
+ public:
+ CacheEntry (WaveView const *, double, double, int);
~CacheEntry ();
- int start () const {
+ double start () const {
return _start;
}
- int end () const {
+ double end () const {
return _end;
}
@@ -130,9 +144,11 @@ private:
Coord position (Coord) const;
WaveView const * _wave_view;
- int _start;
- int _end;
- int _n_peaks;
+
+ double _start;
+ double _end;
+ int _n_peaks;
+
boost::shared_array<ARDOUR::PeakData> _peaks;
Cairo::RefPtr<Cairo::ImageSurface> _image;
};
@@ -163,7 +179,7 @@ private:
* value as the crossfade editor needs to alter it.
*/
ARDOUR::frameoffset_t _region_start;
-
+
mutable std::list<CacheEntry*> _cache;
PBD::ScopedConnection invalidation_connection;
diff --git a/libs/canvas/group.cc b/libs/canvas/group.cc
index fe783ad8b5..1272d0e438 100644
--- a/libs/canvas/group.cc
+++ b/libs/canvas/group.cc
@@ -88,7 +88,7 @@ Group::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
if (!(*i)->visible ()) {
#ifdef CANVAS_DEBUG
if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
- cerr << _canvas->render_indent() << "Item " << (*i)->whatami() << " [" << (*i)->name << "] invisible - skipped\n";
+ // cerr << _canvas->render_indent() << "Item " << (*i)->whatami() << " [" << (*i)->name << "] invisible - skipped\n";
}
#endif
continue;
@@ -99,7 +99,7 @@ Group::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
if (!item_bbox) {
#ifdef CANVAS_DEBUG
if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
- cerr << _canvas->render_indent() << "Item " << (*i)->whatami() << " [" << (*i)->name << "] empty - skipped\n";
+ // cerr << _canvas->render_indent() << "Item " << (*i)->whatami() << " [" << (*i)->name << "] empty - skipped\n";
}
#endif
continue;
@@ -127,8 +127,8 @@ Group::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
} else {
#ifdef CANVAS_DEBUG
if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
- cerr << string_compose ("%1skip render of %2 %3, no intersection\n", _canvas->render_indent(), (*i)->whatami(),
- (*i)->name);
+ //cerr << string_compose ("%1skip render of %2 %3, no intersection\n", _canvas->render_indent(), (*i)->whatami(),
+ // (*i)->name);
}
#endif
}
diff --git a/libs/canvas/outline.cc b/libs/canvas/outline.cc
index 15ea4776b6..3e57887070 100644
--- a/libs/canvas/outline.cc
+++ b/libs/canvas/outline.cc
@@ -41,35 +41,33 @@ Outline::Outline (Group* parent)
void
Outline::set_outline_color (Color color)
{
- begin_visual_change ();
-
- _outline_color = color;
-
- end_visual_change ();
+ if (color != _outline_color) {
+ begin_visual_change ();
+ _outline_color = color;
+ end_visual_change ();
+ }
}
void
Outline::set_outline_width (Distance width)
{
- begin_change ();
-
- _outline_width = width;
-
- _bounding_box_dirty = true;
- end_change ();
-
- DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: outline width change\n");
+ if (width != _outline_width) {
+ begin_change ();
+ _outline_width = width;
+ _bounding_box_dirty = true;
+ end_change ();
+ }
}
void
Outline::set_outline (bool outline)
{
- begin_change ();
-
- _outline = outline;
-
- _bounding_box_dirty = true;
- end_change ();
+ if (outline != _outline) {
+ begin_change ();
+ _outline = outline;
+ _bounding_box_dirty = true;
+ end_change ();
+ }
}
void
diff --git a/libs/canvas/wave_view.cc b/libs/canvas/wave_view.cc
index c6ba816288..f39dca7594 100644
--- a/libs/canvas/wave_view.cc
+++ b/libs/canvas/wave_view.cc
@@ -25,6 +25,7 @@
#include "pbd/compose.h"
#include "pbd/signals.h"
+#include "pbd/stacktrace.h"
#include "ardour/types.h"
#include "ardour/dB.h"
@@ -65,7 +66,7 @@ WaveView::WaveView (Group* parent, boost::shared_ptr<ARDOUR::AudioRegion> region
, _logscaled_independent (false)
, _gradient_depth_independent (false)
, _amplitude_above_axis (1.0)
- , _region_start (0)
+ , _region_start (region->start())
{
VisualPropertiesChanged.connect_same_thread (invalidation_connection, boost::bind (&WaveView::handle_visual_property_change, this));
}
@@ -98,28 +99,47 @@ WaveView::handle_visual_property_change ()
void
WaveView::set_fill_color (Color c)
{
- invalidate_image_cache ();
- Fill::set_fill_color (c);
+ if (c != _fill_color) {
+ invalidate_image_cache ();
+ Fill::set_fill_color (c);
+ }
}
void
WaveView::set_outline_color (Color c)
{
- invalidate_image_cache ();
- Outline::set_outline_color (c);
+ if (c != _outline_color) {
+ invalidate_image_cache ();
+ Outline::set_outline_color (c);
+ }
}
void
WaveView::set_samples_per_pixel (double samples_per_pixel)
{
- begin_change ();
+ if (samples_per_pixel != _samples_per_pixel) {
+ begin_change ();
- _samples_per_pixel = samples_per_pixel;
+ _samples_per_pixel = samples_per_pixel;
+
+ _bounding_box_dirty = true;
+
+ end_change ();
+
+ invalidate_whole_cache ();
+ }
+}
- _bounding_box_dirty = true;
- end_change ();
+static inline double
+to_src_sample_offset (frameoffset_t src_sample_start, double pixel_offset, double spp)
+{
+ return src_sample_start + (pixel_offset * spp);
+}
- invalidate_whole_cache ();
+static inline double
+to_pixel_offset (frameoffset_t src_sample_start, double sample_offset, double spp)
+{
+ return (sample_offset - src_sample_start) / spp;
}
void
@@ -131,53 +151,91 @@ WaveView::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) cons
return;
}
- /* p, start and end are offsets from the start of the source.
- area is relative to the position of the region.
+ /* These are all pixel (integer) coordinates from the left hand edge of
+ * the waveview.
*/
- int const start = rint (area.x0 + _region_start / _samples_per_pixel);
- int const end = rint (area.x1 + _region_start / _samples_per_pixel);
+ double start = area.x0;
+ double const end = area.x1;
+ double const rend = _region->length() / _samples_per_pixel;
- int p = start;
list<CacheEntry*>::iterator cache = _cache.begin ();
- while (p < end) {
+ while ((end - start) > 1.0) {
+
+ frameoffset_t start_sample_offset = to_src_sample_offset (_region_start, start, _samples_per_pixel);
- /* Step through cache entries that end at or before our current position, p */
- while (cache != _cache.end() && (*cache)->end() <= p) {
+ /* Step through cache entries that end at or before our current position */
+
+ while (cache != _cache.end() && (*cache)->end() <= start_sample_offset) {
++cache;
}
/* Now either:
1. we have run out of cache entries
- 2. the one we are looking at finishes after p but also starts after p.
- 3. the one we are looking at finishes after p and starts before p.
+ 2. the one we are looking at finishes after start(_sample_offset) but also starts after start(_sample_offset).
+ 3. the one we are looking at finishes after start(_sample_offset) and starts before start(_sample_offset).
Set up a pointer to the cache entry that we will use on this iteration.
*/
- CacheEntry* render = 0;
+ CacheEntry* image = 0;
if (cache == _cache.end ()) {
/* Case 1: we have run out of cache entries, so make a new one for
the whole required area and put it in the list.
+
+ We would like to avoid lots of little images in the
+ cache, so when we create a new one, make it as wide
+ as possible, within a sensible limit (here, the
+ visible width of the canvas we're on).
+
+ However, we don't want to try to make it larger than
+ the region actually is, so clamp with that too.
*/
-
- CacheEntry* c = new CacheEntry (this, p, end);
+
+ double const endpoint = min (rend, max (end, start + _canvas->visible_area().width()));
+ CacheEntry* c = new CacheEntry (this,
+ start_sample_offset,
+ to_src_sample_offset (_region_start, endpoint, _samples_per_pixel),
+ endpoint - start);
_cache.push_back (c);
- render = c;
+ image = c;
- } else if ((*cache)->start() > p) {
+ } else if ((*cache)->start() > start_sample_offset) {
- /* Case 2: we have a cache entry, but it starts after p, so we
- need another one for the missing bit.
- */
+ /* Case 2: we have a cache entry, but it starts after
+ * start(_sample_offset), so we need another one for
+ * the missing bit.
+ *
+ * Create a new cached image that extends as far as the
+ * next cached image's start, or the end of the region,
+ * or the end of the render area, whichever comes first.
+ */
+
+ double end_pixel = min (rend, end);
+ double end_sample_offset = to_src_sample_offset (_region_start, end_pixel, _samples_per_pixel);
+ int npeaks;
+
+ if (end_sample_offset < (*cache)->start()) {
+ npeaks = end_pixel - start;
+ assert (npeaks > 0);
+ } else {
+ end_sample_offset = (*cache)->start();
+ end_pixel = to_pixel_offset (_region_start, end_sample_offset, _samples_per_pixel);
+ npeaks = end_pixel - npeaks;
+ assert (npeaks > 0);
+ }
+
+ CacheEntry* c = new CacheEntry (this,
+ start_sample_offset,
+ end_sample_offset,
+ npeaks);
- CacheEntry* c = new CacheEntry (this, p, min (end, (*cache)->start()));
cache = _cache.insert (cache, c);
++cache;
- render = c;
+ image = c;
} else {
@@ -185,29 +243,19 @@ WaveView::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) cons
we have left, so render it.
*/
- render = *cache;
+ image = *cache;
++cache;
}
- int const this_end = min (end, render->end ());
-
- Coord const left = p - _region_start / _samples_per_pixel;
- Coord const right = this_end - _region_start / _samples_per_pixel;
-
- context->save ();
-
- context->rectangle (left, area.y0, right, area.height());
- context->clip ();
-
- context->translate (left, 0);
+ double this_end = min (end, to_pixel_offset (_region_start, image->end (), _samples_per_pixel));
+ double const image_origin = to_pixel_offset (_region_start, image->start(), _samples_per_pixel);
- context->set_source (render->image(), render->start() - p, 0);
- context->paint ();
+ context->rectangle (start, area.y0, this_end - start, area.height());
+ context->set_source (image->image(), image_origin, 0);
+ context->fill ();
- context->restore ();
-
- p = min (end, render->end ());
+ start = this_end;
}
}
@@ -215,7 +263,7 @@ void
WaveView::compute_bounding_box () const
{
if (_region) {
- _bounding_box = Rect (0, 0, _region->length() / _samples_per_pixel, _height);
+ _bounding_box = Rect (0.0, 0.0, _region->length() / _samples_per_pixel, _height);
} else {
_bounding_box = boost::optional<Rect> ();
}
@@ -226,33 +274,38 @@ WaveView::compute_bounding_box () const
void
WaveView::set_height (Distance height)
{
- begin_change ();
-
- _height = height;
-
- _bounding_box_dirty = true;
- end_change ();
-
- invalidate_image_cache ();
+ if (height != _height) {
+ begin_change ();
+
+ _height = height;
+
+ _bounding_box_dirty = true;
+ end_change ();
+
+ invalidate_image_cache ();
+ }
}
void
WaveView::set_channel (int channel)
{
- begin_change ();
-
- _channel = channel;
-
- _bounding_box_dirty = true;
- end_change ();
-
- invalidate_whole_cache ();
+ if (channel != _channel) {
+ begin_change ();
+
+ _channel = channel;
+
+ _bounding_box_dirty = true;
+ end_change ();
+
+ invalidate_whole_cache ();
+ }
}
void
WaveView::invalidate_whole_cache ()
{
begin_visual_change ();
+
for (list<CacheEntry*>::iterator i = _cache.begin(); i != _cache.end(); ++i) {
delete *i;
}
@@ -266,7 +319,7 @@ void
WaveView::invalidate_image_cache ()
{
begin_visual_change ();
-
+
for (list<CacheEntry*>::iterator i = _cache.begin(); i != _cache.end(); ++i) {
(*i)->clear_image ();
}
@@ -275,12 +328,6 @@ WaveView::invalidate_image_cache ()
}
void
-WaveView::region_resized ()
-{
- _bounding_box_dirty = true;
-}
-
-void
WaveView::set_logscaled (bool yn)
{
if (_logscaled != yn) {
@@ -360,31 +407,41 @@ WaveView::set_global_logscaled (bool yn)
}
void
-WaveView::set_region_start (frameoffset_t start)
+WaveView::region_resized ()
{
- _region_start = start;
+ if (!_region) {
+ return;
+ }
+
+ /* special: do not use _region->length() here to compute
+ bounding box because it will already have changed.
+
+ if we have a bounding box, use it.
+ */
+
+ _pre_change_bounding_box = _bounding_box;
+
+ _region_start = _region->start();
+ invalidate_whole_cache ();
+
_bounding_box_dirty = true;
+ compute_bounding_box ();
+
+ end_change ();
}
-/** Construct a new CacheEntry with peak data between two offsets
- * in the source.
- */
-WaveView::CacheEntry::CacheEntry (WaveView const * wave_view, int start, int end)
+WaveView::CacheEntry::CacheEntry (WaveView const * wave_view, double start, double end, int npeaks)
: _wave_view (wave_view)
, _start (start)
, _end (end)
+ , _n_peaks (npeaks)
{
- _n_peaks = _end - _start;
_peaks.reset (new PeakData[_n_peaks]);
- _wave_view->_region->read_peaks (
- _peaks.get(),
- _n_peaks,
- _start * _wave_view->_samples_per_pixel,
- (_end - _start) * _wave_view->_samples_per_pixel,
- _wave_view->_channel,
- _wave_view->_samples_per_pixel
- );
+ _wave_view->_region->read_peaks (_peaks.get(), _n_peaks,
+ (framecnt_t) floor (_start),
+ (framecnt_t) ceil (_end),
+ _wave_view->_channel, _wave_view->_samples_per_pixel);
}
WaveView::CacheEntry::~CacheEntry ()