bc2c2c100a61dc313d89a657bf54a0cc6ee0dd0f
[ardour.git] / libs / canvas / line_set.cc
1 /*
2     Copyright (C) 2011-2013 Paul Davis
3     Author: Carl Hetherington <cth@carlh.net>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "canvas/line_set.h"
21 #include "canvas/utils.h"
22
23 using namespace std;
24 using namespace ArdourCanvas;
25
26 /* XXX: hard-wired to horizontal only */
27
28 class LineSorter {
29 public:
30         bool operator() (LineSet::Line& a, LineSet::Line& b) {
31                 return a.y < b.y;
32         }
33 };
34
35 LineSet::LineSet (Group* parent)
36         : Item (parent)
37         , _height (0)
38 {
39
40 }
41
42
43 void
44 LineSet::compute_bounding_box () const
45 {
46         if (_lines.empty ()) {
47                 _bounding_box = boost::optional<Rect> ();
48                 _bounding_box_dirty = false;
49                 return;
50         }
51         
52         _bounding_box = Rect (0, _lines.front().y, COORD_MAX, min (_height, _lines.back().y));
53         _bounding_box_dirty = false;
54 }
55
56 void
57 LineSet::set_height (Distance height)
58 {
59         begin_change ();
60
61         _height = height;
62
63         _bounding_box_dirty = true;
64         end_change ();
65 }
66
67 void
68 LineSet::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
69 {
70         /* area is in window coordinates */
71
72         for (list<Line>::const_iterator i = _lines.begin(); i != _lines.end(); ++i) {
73
74                 Duple self = item_to_window (Duple (area.x0, i->y));
75
76                 if (self.y > area.y1) {
77                         /* line is past the ymax for the render rect, nothing
78                            to draw 
79                         */
80                         break;
81                 } else if (self.y > area.y0) {
82                         /* line is between ymin and ymax for the render rect,
83                            draw something.
84                         */
85                         set_source_rgba (context, i->color);
86                         context->set_line_width (i->width);
87                         context->move_to (area.x0, self.y);
88                         context->line_to (area.x1, self.y);
89                         context->stroke ();
90                 }
91         }
92 }
93
94 void
95 LineSet::add (Coord y, Distance width, Color color)
96 {
97         begin_change ();
98         
99         _lines.push_back (Line (y, width, color));
100         _lines.sort (LineSorter ());
101
102         _bounding_box_dirty = true;
103         end_change ();
104 }
105
106 void
107 LineSet::clear ()
108 {
109         begin_change ();
110         _lines.clear ();
111         _bounding_box_dirty = true;
112         end_change ();
113 }