From 7a3a66db725793e00f26fd722861f4c5cc819285 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 9 Jun 2014 15:39:19 -0400 Subject: [PATCH] fix Canvas::LineSet implementation to support horizontal and vertical linesets --- libs/canvas/canvas/fwd.h | 1 + libs/canvas/canvas/line_set.h | 21 ++++++--- libs/canvas/line_set.cc | 80 +++++++++++++++++++++++++++-------- 3 files changed, 78 insertions(+), 24 deletions(-) diff --git a/libs/canvas/canvas/fwd.h b/libs/canvas/canvas/fwd.h index 1e812f9144..b8242e86bb 100644 --- a/libs/canvas/canvas/fwd.h +++ b/libs/canvas/canvas/fwd.h @@ -24,6 +24,7 @@ namespace ArdourCanvas { class WaveView; class Line; + class LineSet; class Rectangle; class Polygon; class PolyLine; diff --git a/libs/canvas/canvas/line_set.h b/libs/canvas/canvas/line_set.h index a9b13651d9..69f2b96907 100644 --- a/libs/canvas/canvas/line_set.h +++ b/libs/canvas/canvas/line_set.h @@ -17,6 +17,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifndef __CANVAS_LINESET_H__ +#define __CANVAS_LINESET_H__ + +#include + #include "canvas/visibility.h" #include "canvas/item.h" @@ -30,29 +35,33 @@ public: Horizontal }; - LineSet (Group *); + LineSet (Group *, Orientation o = Vertical); void compute_bounding_box () const; void render (Rect const & area, Cairo::RefPtr) const; bool covers (Duple const &) const; - void set_height (Distance); + void set_extent (Distance); + Distance extent() const { return _extent; } void add (Coord, Distance, Color); void clear (); struct Line { - Line (Coord y_, Distance width_, Color color_) : y (y_), width (width_), color (color_) {} + Line (Coord p, Distance width_, Color color_) : pos (p), width (width_), color (color_) {} - Coord y; + Coord pos; Distance width; Color color; }; private: - std::list _lines; - Distance _height; + std::vector _lines; + Distance _extent; + Orientation _orientation; }; } + +#endif /* __CANVAS_LINESET_H__ */ diff --git a/libs/canvas/line_set.cc b/libs/canvas/line_set.cc index 1625e0478d..0cc4690f76 100644 --- a/libs/canvas/line_set.cc +++ b/libs/canvas/line_set.cc @@ -23,42 +23,57 @@ using namespace std; using namespace ArdourCanvas; -/* XXX: hard-wired to horizontal only */ - class LineSorter { public: - bool operator() (LineSet::Line& a, LineSet::Line& b) { - return a.y < b.y; + bool operator() (LineSet::Line const & a, LineSet::Line const & b) { + return a.pos < b.pos; } }; -LineSet::LineSet (Group* parent) +LineSet::LineSet (Group* parent, Orientation o) : Item (parent) - , _height (0) + , _extent (0) + , _orientation (o) { } - void LineSet::compute_bounding_box () const { if (_lines.empty ()) { _bounding_box = boost::optional (); } else { - _bounding_box = Rect (0, _lines.front().y - (_lines.front().width/2.0), COORD_MAX, min (_height, _lines.back().y - (_lines.back().width/2.0))); + + if (_orientation == Horizontal) { + + _bounding_box = Rect (0, /* x0 */ + _lines.front().pos - (_lines.front().width/2.0), /* y0 */ + _extent, /* x1 */ + _lines.back().pos - (_lines.back().width/2.0) /* y1 */ + ); + + } else { + + _bounding_box = Rect (_lines.front().pos - _lines.front().width/2.0, /* x0 */ + 0, /* y0 */ + _lines.back().pos + _lines.back().width/2.0, /* x1 */ + _extent /* y1 */ + ); + } } + _bounding_box_dirty = false; } void -LineSet::set_height (Distance height) +LineSet::set_extent (Distance e) { begin_change (); - _height = height; - + _extent = e; _bounding_box_dirty = true; + end_change (); } @@ -67,19 +82,42 @@ LineSet::render (Rect const & area, Cairo::RefPtr context) const { /* area is in window coordinates */ - for (list::const_iterator i = _lines.begin(); i != _lines.end(); ++i) { + for (vector::const_iterator i = _lines.begin(); i != _lines.end(); ++i) { + + Rect self; - Rect self = item_to_window (Rect (0, i->y - (i->width/2.0), COORD_MAX, i->y + (i->width/2.0))); - boost::optional intersect = self.intersection (area); + if (_orientation == Horizontal) { + self = item_to_window (Rect (0, i->pos - (i->width/2.0), _extent, i->pos + (i->width/2.0))); + } else { + self = item_to_window (Rect (i->pos - (i->width/2.0), 0, i->pos + (i->width/2.0), _extent)); + } + + boost::optional isect = self.intersection (area); - if (!intersect) { + if (!isect) { continue; } + Rect intersection (isect.get()); + set_source_rgba (context, i->color); context->set_line_width (i->width); - context->move_to (intersect->x0, self.y0 + ((self.y1 - self.y0)/2.0)); - context->line_to (intersect->x1, self.y0 + ((self.y1 - self.y0)/2.0)); + + /* Not 100% sure that the computation of the invariant + * positions (y and x) below work correctly if the line width + * is not 1.0, but visual inspection suggests it is OK. + */ + + if (_orientation == Horizontal) { + double y = self.y0 + ((self.y1 - self.y0)/2.0); + context->move_to (intersection.x0, y); + context->line_to (intersection.x1, y); + } else { + double x = self.x0 + ((self.x1 - self.x0)/2.0); + context->move_to (x, intersection.y0); + context->line_to (x, intersection.y1); + } + context->stroke (); } } @@ -90,7 +128,7 @@ LineSet::add (Coord y, Distance width, Color color) begin_change (); _lines.push_back (Line (y, width, color)); - _lines.sort (LineSorter ()); + sort (_lines.begin(), _lines.end(), LineSorter()); _bounding_box_dirty = true; end_change (); @@ -108,5 +146,11 @@ LineSet::clear () bool LineSet::covers (Duple const & /*point*/) const { + /* lines are ordered by position along primary axis, so binary search + * to find the place to start looking. + * + * XXX but not yet. + */ + return false; } -- 2.30.2