different approach to independent scrolling, involving ArdourCanvas::ScrollGroup

The idea now is that a scroll group item can be added to the canvas which will causes its children to scroll in either or both
directions (horizontal or vertical). There are few complications: the position() of the ScrollGroup is ambiguous depending
on whether you want it with scroll taken into account or not, so Item::canvas_position() was added, which defaults to
the same value as Item::position() but is overridden by ScrollGroup to return the position independent of scrolling. This
method is used when translating between item/canvas/window coordinate systems.

Note that the basic idea is that we MOVE the scroll group when a scroll happens. This mirrors what happens in the GnomeCanvas,
where Nick Mainsbridge came up with a great idea that allowed unification of the time bar and track canvases.
This commit is contained in:
Paul Davis 2014-05-20 23:08:15 -04:00
parent 6e91e9fd5f
commit cb9453b475
14 changed files with 200 additions and 122 deletions

View file

@ -742,7 +742,20 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
ArdourCanvas::Group* transport_marker_bar_group;
ArdourCanvas::Group* cd_marker_bar_group;
/* The group containing all trackviews. Only scrolled vertically. */
/* The group containing all other groups that are scrolled vertically
and horizontally.
*/
ArdourCanvas::Group* hv_scroll_group;
/* The group containing all other groups that are scrolled vertically ONLY
*/
ArdourCanvas::Group* v_scroll_group;
/* The group containing all other groups that are scrolled horizontally ONLY
*/
ArdourCanvas::Group* h_scroll_group;
/* The group containing all trackviews. */
ArdourCanvas::Group* _trackview_group;
/* The group used for region motion. Sits on top of _trackview_group */

View file

@ -30,6 +30,7 @@
#include "canvas/canvas.h"
#include "canvas/rectangle.h"
#include "canvas/pixbuf.h"
#include "canvas/scroll_group.h"
#include "canvas/text.h"
#include "canvas/debug.h"
@ -65,7 +66,12 @@ Editor::initialize_canvas ()
{
_track_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, vertical_adjustment);
_track_canvas = _track_canvas_viewport->canvas ();
//_track_canvas->set_global_scroll (false);
_track_canvas->set_global_scroll (false);
hv_scroll_group = new ArdourCanvas::ScrollGroup (_track_canvas->root(),
ArdourCanvas::ScrollGroup::ScrollSensitivity (ArdourCanvas::ScrollGroup::ScrollsVertically|
ArdourCanvas::ScrollGroup::ScrollsHorizontally));
CANVAS_DEBUG_NAME (hv_scroll_group, "canvas hv scroll");
_verbose_cursor = new VerboseCursor (this);
@ -80,9 +86,9 @@ Editor::initialize_canvas ()
// logo_item->property_width_set() = true;
// logo_item->show ();
}
/*a group to hold global rects like punch/loop indicators */
global_rect_group = new ArdourCanvas::Group (_track_canvas->root());
global_rect_group = new ArdourCanvas::Group (hv_scroll_group);
CANVAS_DEBUG_NAME (global_rect_group, "global rect group");
transport_loop_range_rect = new ArdourCanvas::Rectangle (global_rect_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, ArdourCanvas::COORD_MAX));
@ -94,21 +100,20 @@ Editor::initialize_canvas ()
transport_punch_range_rect->hide();
/*a group to hold time (measure) lines */
time_line_group = new ArdourCanvas::Group (_track_canvas->root());
time_line_group = new ArdourCanvas::Group (hv_scroll_group);
CANVAS_DEBUG_NAME (time_line_group, "time line group");
_trackview_group = new ArdourCanvas::Group (_track_canvas->root());
_trackview_group = new ArdourCanvas::Group (hv_scroll_group);
//_trackview_group->set_scroll_sensitivity (ArdourCanvas::Group::ScrollSensitivity (ArdourCanvas::Group::ScrollsVertically|ArdourCanvas::Group::ScrollsHorizontally));
CANVAS_DEBUG_NAME (_trackview_group, "Canvas TrackViews");
_region_motion_group = new ArdourCanvas::Group (_trackview_group);
CANVAS_DEBUG_NAME (_region_motion_group, "Canvas Region Motion");
/* TIME BAR CANVAS */
_time_bars_canvas_viewport = new ArdourCanvas::GtkCanvasViewport (horizontal_adjustment, unused_adjustment);
_time_bars_canvas = _time_bars_canvas_viewport->canvas ();
_region_motion_group = new ArdourCanvas::Group (_trackview_group);
CANVAS_DEBUG_NAME (_region_motion_group, "Canvas Region Motion");
meter_bar_group = new ArdourCanvas::Group (_time_bars_canvas->root ());
meter_bar = new ArdourCanvas::Rectangle (meter_bar_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, timebar_height));
@ -177,14 +182,14 @@ Editor::initialize_canvas ()
transport_bar_drag_rect->set_outline (false);
transport_bar_drag_rect->hide ();
transport_punchin_line = new ArdourCanvas::Line (_track_canvas->root());
transport_punchin_line = new ArdourCanvas::Line (hv_scroll_group);
transport_punchin_line->set_x0 (0);
transport_punchin_line->set_y0 (0);
transport_punchin_line->set_x1 (0);
transport_punchin_line->set_y1 (ArdourCanvas::COORD_MAX);
transport_punchin_line->hide ();
transport_punchout_line = new ArdourCanvas::Line (_track_canvas->root());
transport_punchout_line = new ArdourCanvas::Line (hv_scroll_group);
transport_punchout_line->set_x0 (0);
transport_punchout_line->set_y0 (0);
transport_punchout_line->set_x1 (0);
@ -192,12 +197,12 @@ Editor::initialize_canvas ()
transport_punchout_line->hide();
// used to show zoom mode active zooming
zoom_rect = new ArdourCanvas::Rectangle (_track_canvas->root(), ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
zoom_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
zoom_rect->hide();
zoom_rect->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_zoom_rect_event), (ArdourCanvas::Item*) 0));
// used as rubberband rect
rubberband_rect = new ArdourCanvas::Rectangle (_trackview_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
rubberband_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, 0.0, 0.0));
rubberband_rect->hide();
tempo_bar->Event.connect (sigc::bind (sigc::mem_fun (*this, &Editor::canvas_tempo_bar_event), tempo_bar));
@ -215,7 +220,7 @@ Editor::initialize_canvas ()
}
_canvas_bottom_rect = new ArdourCanvas::Rectangle (_track_canvas->root(), ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, 20));
_canvas_bottom_rect = new ArdourCanvas::Rectangle (hv_scroll_group, ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, 20));
/* this thing is transparent */
_canvas_bottom_rect->set_fill (false);
_canvas_bottom_rect->set_outline (false);
@ -591,8 +596,6 @@ Editor::autoscroll_canvas ()
/* vertical */
new_pixel = vertical_pos;
if (y < autoscroll_boundary.y0) {
/* scroll to make higher tracks visible */
@ -931,7 +934,7 @@ Editor::get_time_bars_group () const
ArdourCanvas::Group*
Editor::get_track_canvas_group() const
{
return _track_canvas->root();
return hv_scroll_group;
}
ArdourCanvas::GtkCanvasViewport*

View file

@ -33,8 +33,8 @@ using namespace Gtk;
EditorCursor::EditorCursor (Editor& ed, bool (Editor::*callbck)(GdkEvent*,ArdourCanvas::Item*))
: _editor (ed)
, _time_bars_canvas_item (new ArdourCanvas::Arrow (_editor._time_bars_canvas->root ()))
, _track_canvas_item (new ArdourCanvas::Line (_editor._track_canvas->root ()))
, _time_bars_canvas_item (new ArdourCanvas::Arrow (_editor.get_time_bars_group()))
, _track_canvas_item (new ArdourCanvas::Line (_editor.get_track_canvas_group()))
, _length (1.0)
{
CANVAS_DEBUG_NAME (_time_bars_canvas_item, "timebars editor cursor");

View file

@ -134,18 +134,22 @@ Editor::mouse_frame (framepos_t& where, bool& in_track_canvas) const
framepos_t
Editor::window_event_sample (GdkEvent const * event, double* pcx, double* pcy) const
{
double x;
double y;
ArdourCanvas::Duple d;
if (!gdk_event_get_coords (event, &x, &y)) {
if (!gdk_event_get_coords (event, &d.x, &d.y)) {
return 0;
}
/* event coordinates are in window units, so convert to canvas
* (i.e. account for scrolling)
/* adjust for scrolling (the canvas used by Ardour has global scroll
* disabled, so we have to do the adjustment explicitly).
*/
ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (x, y));
d.translate (ArdourCanvas::Duple (horizontal_adjustment.get_value(), vertical_adjustment.get_value()));
/* event coordinates are in window units, so convert to canvas
*/
d = _track_canvas->window_to_canvas (d);
if (pcx) {
*pcx = d.x;
@ -317,7 +321,7 @@ Editor::set_canvas_cursor ()
vector<ArdourCanvas::Item const *> items;
_track_canvas->root()->add_items_at_point (ArdourCanvas::Duple (x,y), items);
get_track_canvas_group()->add_items_at_point (ArdourCanvas::Duple (x,y), items);
// first item will be the upper most
@ -2101,7 +2105,6 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type)
AutomationLine* al;
Marker *marker;
Location *loc;
RegionView* rv;
bool is_start;
bool ret = true;
@ -2186,7 +2189,6 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type)
case FadeOutTrimHandleItem:
case FadeInHandleItem:
case FadeOutHandleItem:
rv = static_cast<RegionView*>(item->get_data ("regionview"));
{
ArdourCanvas::Rectangle *rect = dynamic_cast<ArdourCanvas::Rectangle *> (item);
if (rect) {

View file

@ -43,7 +43,7 @@ VerboseCursor::VerboseCursor (Editor* editor)
, _xoffset (0)
, _yoffset (0)
{
_canvas_item = new ArdourCanvas::Text (_editor->_track_canvas->root());
_canvas_item = new ArdourCanvas::Text (_editor->get_track_canvas_group());
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")));

View file

@ -50,11 +50,9 @@ Canvas::scroll_to (Coord x, Coord y)
{
Duple d (x, y);
if (_global_scroll) {
_scroll_offset = d;
}
//_root.scroll_to (d);
_scroll_offset = d;
_root.scroll_to (d);
pick_current_item (0); // no current mouse position
}
@ -81,9 +79,9 @@ Canvas::render (Rect const & area, Cairo::RefPtr<Cairo::Context> const & context
#ifdef CANVAS_DEBUG
if (DEBUG_ENABLED(PBD::DEBUG::CanvasRender)) {
cerr << this << " RENDER: " << area << endl;
cerr << "CANVAS @ " << this << endl;
dump (cerr);
cerr << "-------------------------\n";
//cerr << "CANVAS @ " << this << endl;
//dump (cerr);
//cerr << "-------------------------\n";
}
#endif
@ -208,13 +206,14 @@ Canvas::canvas_to_window (Duple const & d, bool rounded) const
Duple wd = d.translate (Duple (-_scroll_offset.x, -_scroll_offset.y));
/* Note that this intentionally almost always returns integer coordinates */
if (rounded) {
wd.x = round (wd.x);
wd.y = round (wd.y);
}
return wd;
}
}
Rect
Canvas::window_to_canvas (Rect const & r) const

View file

@ -112,22 +112,17 @@ public:
void set_y_position (Coord);
void move (Duple);
enum ScrollSensitivity {
ScrollsVertically = 0x1,
ScrollsHorizontally = 0x2
};
void set_scroll_sensitivity (ScrollSensitivity s);
ScrollSensitivity scroll_sensitivity () const { return _scroll_sensitivity; }
virtual void scroll_to (Duple const& d);
Duple scroll_offset() const { return _scroll_offset; }
virtual void scroll_to (Duple const&) {}
/** @return Position of this item in the parent's coordinates */
Duple position () const {
return _position;
}
virtual Duple canvas_position () const {
return _position;
}
boost::optional<Rect> bounding_box () const;
Coord height() const;
Coord width() const;
@ -248,8 +243,6 @@ private:
void init ();
bool _ignore_events;
ScrollSensitivity _scroll_sensitivity;
Duple _scroll_offset;
};
extern LIBCANVAS_API std::ostream& operator<< (std::ostream&, const ArdourCanvas::Item&);

View file

@ -0,0 +1,47 @@
/*
Copyright (C) 2014 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __CANVAS_SCROLL_GROUP_H__
#define __CANVAS_SCROLL_GROUP_H__
#include "canvas/group.h"
namespace ArdourCanvas {
class LIBCANVAS_API ScrollGroup : public Group
{
public:
enum ScrollSensitivity {
ScrollsVertically = 0x1,
ScrollsHorizontally = 0x2
};
explicit ScrollGroup (Group *, ScrollSensitivity);
explicit ScrollGroup (Group *, Duple, ScrollSensitivity);
void scroll_to (Duple const& d);
Duple canvas_position() const;
private:
ScrollSensitivity _scroll_sensitivity;
Duple _scroll_offset;
};
}
#endif

View file

@ -173,7 +173,7 @@ private:
void handle_clip_level_change ();
void ensure_cache (ARDOUR::framepos_t sample_start, ARDOUR::framepos_t sample_end) const;
ArdourCanvas::Coord position (double) const;
ArdourCanvas::Coord y_extent (double) const;
void draw_image (ARDOUR::PeakData*, int npeaks) const;
};

View file

@ -117,7 +117,9 @@ Group::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
<< (*i)->whatami()
<< ' '
<< (*i)->name
<< " item = "
<< " item "
<< item_bbox.get()
<< " window = "
<< item
<< " intersect = "
<< draw
@ -136,8 +138,8 @@ Group::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
#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 between %4 and %5\n", _canvas->render_indent(), (*i)->whatami(),
(*i)->name, item, area);
}
#endif
@ -152,7 +154,7 @@ Group::scroll_to (Duple const& d)
{
Item::scroll_to (d);
for (list<Item*>::iterator i = _items.begin(); i != _items.end(); ) {
for (list<Item*>::iterator i = _items.begin(); i != _items.end(); ++i) {
(*i)->scroll_to (d);
}
}

View file

@ -35,7 +35,6 @@ using namespace ArdourCanvas;
Item::Item (Canvas* canvas)
: _canvas (canvas)
, _parent (0)
, _scroll_sensitivity (ScrollSensitivity (0))
{
init ();
}
@ -43,7 +42,6 @@ Item::Item (Canvas* canvas)
Item::Item (Group* parent)
: _canvas (parent->canvas ())
, _parent (parent)
, _scroll_sensitivity (ScrollSensitivity (0))
{
init ();
}
@ -52,7 +50,6 @@ Item::Item (Group* parent, Duple position)
: _canvas (parent->canvas())
, _parent (parent)
, _position (position)
, _scroll_sensitivity (ScrollSensitivity (0))
{
init ();
}
@ -82,24 +79,6 @@ Item::~Item ()
}
}
void
Item::scroll_to (Duple const& d)
{
if (_scroll_sensitivity & ScrollsVertically) {
_scroll_offset.y = d.y;
}
if (_scroll_sensitivity & ScrollsHorizontally) {
_scroll_offset.x = d.x;
}
}
void
Item::set_scroll_sensitivity (ScrollSensitivity s)
{
_scroll_sensitivity = s;
}
ArdourCanvas::Rect
Item::item_to_parent (ArdourCanvas::Rect const & r) const
{
@ -113,7 +92,7 @@ Item::item_to_canvas (ArdourCanvas::Rect const & r) const
Duple offset;
while (i) {
offset = offset.translate (i->position());
offset = offset.translate (i->canvas_position());
i = i->parent();
}
@ -127,7 +106,7 @@ Item::item_to_canvas (ArdourCanvas::Duple const & d) const
Duple offset;
while (i) {
offset = offset.translate (i->position());
offset = offset.translate (i->canvas_position());
i = i->parent();
}
@ -141,7 +120,7 @@ Item::canvas_to_item (ArdourCanvas::Duple const & d) const
Duple offset;
while (i) {
offset = offset.translate (-(i->position()));
offset = offset.translate (-(i->canvas_position()));
i = i->parent();
}
@ -155,7 +134,7 @@ Item::canvas_to_item (ArdourCanvas::Rect const & d) const
Duple offset;
while (i) {
offset = offset.translate (-(i->position()));
offset = offset.translate (-(i->canvas_position()));
i = i->parent();
}
@ -197,43 +176,19 @@ Item::item_to_window (ArdourCanvas::Duple const & d, bool rounded) const
Duple
Item::window_to_item (ArdourCanvas::Duple const & d) const
{
Item const * i = this;
Duple offset;
while (i) {
offset = offset.translate (-i->scroll_offset());
i = i->parent();
}
return _canvas->window_to_canvas (d.translate (offset));
return canvas_to_item (_canvas->window_to_canvas (d));
}
ArdourCanvas::Rect
Item::item_to_window (ArdourCanvas::Rect const & r) const
{
Item const * i = this;
Duple offset;
while (i) {
offset = offset.translate (i->scroll_offset());
i = i->parent();
}
return _canvas->canvas_to_window (item_to_canvas (r.translate (offset)));
return _canvas->canvas_to_window (item_to_canvas (r));
}
ArdourCanvas::Rect
Item::window_to_item (ArdourCanvas::Rect const & r) const
{
Item const * i = this;
Duple offset;
while (i) {
offset = offset.translate (-i->scroll_offset());
i = i->parent();
}
return canvas_to_item (_canvas->window_to_canvas (r).translate (offset));
return canvas_to_item (_canvas->window_to_canvas (r));
}
/** Set the position of this item in the parent's coordinates */
@ -576,7 +531,7 @@ Item::dump (ostream& o) const
boost::optional<ArdourCanvas::Rect> bb = bounding_box();
o << _canvas->indent() << whatami() << ' ' << this << " Visible ? " << _visible;
o << " @ " << position() << " scrolled-to " << _scroll_offset;
o << " @ " << position();
#ifdef CANVAS_DEBUG
if (!name.empty()) {

View file

@ -0,0 +1,63 @@
/*
Copyright (C) 2014 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <iostream>
#include "canvas/scroll_group.h"
using namespace std;
using namespace ArdourCanvas;
ScrollGroup::ScrollGroup (Group* parent, ScrollSensitivity s)
: Group (parent)
, _scroll_sensitivity (s)
{
}
ScrollGroup::ScrollGroup (Group* parent, Duple position, ScrollSensitivity s)
: Group (parent, position)
, _scroll_sensitivity (s)
{
}
void
ScrollGroup::scroll_to (Duple const& d)
{
Duple base_pos (position().translate (_scroll_offset));
if (_scroll_sensitivity & ScrollsHorizontally) {
base_pos.x -= d.x;
_scroll_offset.x = d.x;
}
if (_scroll_sensitivity & ScrollsVertically) {
base_pos.y -= d.y;
_scroll_offset.y = d.y;
}
set_position (base_pos);
}
Duple
ScrollGroup::canvas_position() const
{
/* return the normal "base" position of this item
rather its position as affected by any scroll
offset.
*/
return _position.translate (_scroll_offset);
}

View file

@ -219,7 +219,7 @@ WaveView::draw_image (PeakData* _peaks, int n_peaks) const
if (_logscaled) {
for (int i = 0; i < n_peaks; ++i) {
tips[i].bot = height();
tips[i].top = position (alt_log_meter (fast_coefficient_to_dB (max (fabs (_peaks[i].max), fabs (_peaks[i].min)))));
tips[i].top = y_extent (alt_log_meter (fast_coefficient_to_dB (max (fabs (_peaks[i].max), fabs (_peaks[i].min)))));
if (fabs (_peaks[i].max) >= clip_level) {
tips[i].clip_max = true;
@ -231,7 +231,7 @@ WaveView::draw_image (PeakData* _peaks, int n_peaks) const
}
} else {for (int i = 0; i < n_peaks; ++i) {
tips[i].bot = height();
tips[i].top = position (max (fabs (_peaks[i].max), fabs (_peaks[i].min)));
tips[i].top = y_extent (max (fabs (_peaks[i].max), fabs (_peaks[i].min)));
if (fabs (_peaks[i].max) >= clip_level) {
tips[i].clip_max = true;
@ -259,19 +259,19 @@ WaveView::draw_image (PeakData* _peaks, int n_peaks) const
}
if (top > 0.0) {
top = position (alt_log_meter (fast_coefficient_to_dB (top)));
top = y_extent (alt_log_meter (fast_coefficient_to_dB (top)));
} else if (top < 0.0) {
top = position (-alt_log_meter (fast_coefficient_to_dB (-top)));
top = y_extent (-alt_log_meter (fast_coefficient_to_dB (-top)));
} else {
top = position (0.0);
top = y_extent (0.0);
}
if (bot > 0.0) {
bot = position (alt_log_meter (fast_coefficient_to_dB (bot)));
bot = y_extent (alt_log_meter (fast_coefficient_to_dB (bot)));
} else if (bot < 0.0) {
bot = position (-alt_log_meter (fast_coefficient_to_dB (-bot)));
bot = y_extent (-alt_log_meter (fast_coefficient_to_dB (-bot)));
} else {
bot = position (0.0);
bot = y_extent (0.0);
}
tips[i].top = top;
@ -289,8 +289,8 @@ WaveView::draw_image (PeakData* _peaks, int n_peaks) const
tips[i].clip_min = true;
}
tips[i].top = position (_peaks[i].min);
tips[i].bot = position (_peaks[i].max);
tips[i].top = y_extent (_peaks[i].min);
tips[i].bot = y_extent (_peaks[i].max);
}
@ -402,8 +402,8 @@ WaveView::draw_image (PeakData* _peaks, int n_peaks) const
set_source_rgba (context, _zero_color);
context->set_line_width (1.0);
context->move_to (0, position (0.0) + 0.5);
context->line_to (n_peaks, position (0.0) + 0.5);
context->move_to (0, y_extent (0.0) + 0.5);
context->line_to (n_peaks, y_extent (0.0) + 0.5);
context->stroke ();
}
}
@ -668,7 +668,7 @@ WaveView::region_resized ()
}
Coord
WaveView::position (double s) const
WaveView::y_extent (double s) const
{
/* it is important that this returns an integral value, so that we
can ensure correct single pixel behaviour.

View file

@ -50,6 +50,7 @@ canvas_sources = [
'polygon.cc',
'rectangle.cc',
'root_group.cc',
'scroll_group.cc',
'stateful_image.cc',
'text.cc',
'types.cc',