fix Canvas::LineSet implementation to support horizontal and vertical linesets
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 9 Jun 2014 19:39:19 +0000 (15:39 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 9 Jun 2014 19:39:19 +0000 (15:39 -0400)
libs/canvas/canvas/fwd.h
libs/canvas/canvas/line_set.h
libs/canvas/line_set.cc

index 1e812f9144c5ba3c8078eef9528705af9db6fb15..b8242e86bbf226d3689432460211154b1e87805c 100644 (file)
@@ -24,6 +24,7 @@
 namespace ArdourCanvas {
        class WaveView;
        class Line;
+        class LineSet;
        class Rectangle;
        class Polygon;
        class PolyLine;
index a9b13651d9ed9c736c9bc0fb4151865591e62a13..69f2b96907ca8df387633927c8c4339dc2b18cbe 100644 (file)
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#ifndef __CANVAS_LINESET_H__
+#define __CANVAS_LINESET_H__
+
+#include <vector>
+
 #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<Cairo::Context>) 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<Line> _lines;
-       Distance _height;
+       std::vector<Line> _lines;
+       Distance          _extent;
+       Orientation       _orientation;
 };
 
 }
+
+#endif /* __CANVAS_LINESET_H__ */
index 1625e0478dd80cee7fe0e9f15b41664330242648..0cc4690f760897a9dbeb0f105141e6900e07ec65 100644 (file)
 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<Rect> ();
        } 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<Cairo::Context> context) const
 {
        /* area is in window coordinates */
 
-       for (list<Line>::const_iterator i = _lines.begin(); i != _lines.end(); ++i) {
+       for (vector<Line>::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<Rect> 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<Rect> 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;
 }