diff options
-rw-r--r-- | gtk2_ardour/audio_region_view.cc | 121 | ||||
-rw-r--r-- | gtk2_ardour/audio_region_view.h | 1 | ||||
-rw-r--r-- | gtk2_ardour/crossfade_edit.cc | 4 | ||||
-rw-r--r-- | gtk2_ardour/editor.cc | 2 | ||||
-rw-r--r-- | gtk2_ardour/editor_drag.cc | 25 | ||||
-rw-r--r-- | gtk2_ardour/editor_tempodisplay.cc | 3 | ||||
-rw-r--r-- | gtk2_ardour/ghostregion.cc | 5 | ||||
-rw-r--r-- | gtk2_ardour/region_view.cc | 26 | ||||
-rw-r--r-- | gtk2_ardour/region_view.h | 2 | ||||
-rw-r--r-- | gtk2_ardour/streamview.cc | 4 | ||||
-rw-r--r-- | gtk2_ardour/tempo_lines.cc | 10 | ||||
-rw-r--r-- | gtk2_ardour/time_axis_view.cc | 4 | ||||
-rw-r--r-- | gtk2_ardour/time_axis_view_item.cc | 38 | ||||
-rw-r--r-- | gtk2_ardour/time_axis_view_item.h | 3 | ||||
-rw-r--r-- | gtk2_ardour/verbose_cursor.cc | 5 | ||||
-rw-r--r-- | libs/ardour/ardour/region.h | 2 | ||||
-rw-r--r-- | libs/ardour/region.cc | 18 | ||||
-rw-r--r-- | libs/canvas/canvas.cc | 85 | ||||
-rw-r--r-- | libs/canvas/canvas/wave_view.h | 32 | ||||
-rw-r--r-- | libs/canvas/group.cc | 8 | ||||
-rw-r--r-- | libs/canvas/outline.cc | 36 | ||||
-rw-r--r-- | libs/canvas/wave_view.cc | 229 |
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 () |