merge with master, primarily for adrian's maximise-mixer change
[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         } else {
49                 _bounding_box = Rect (0, _lines.front().y - (_lines.front().width/2.0), COORD_MAX, min (_height, _lines.back().y - (_lines.back().width/2.0)));
50         }
51         _bounding_box_dirty = false;
52 }
53
54 void
55 LineSet::set_height (Distance height)
56 {
57         begin_change ();
58
59         _height = height;
60
61         _bounding_box_dirty = true;
62         end_change ();
63 }
64
65 void
66 LineSet::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
67 {
68         /* area is in window coordinates */
69
70         for (list<Line>::const_iterator i = _lines.begin(); i != _lines.end(); ++i) {
71
72                 Rect self = item_to_window (Rect (0, i->y - (i->width/2.0), COORD_MAX, i->y + (i->width/2.0)));
73                 boost::optional<Rect> intersect = self.intersection (area);
74                         
75                 if (!intersect) {
76                         continue;       
77                 }
78
79                 set_source_rgba (context, i->color);
80                 context->set_line_width (i->width);
81                 context->move_to (intersect->x0, self.y0 + ((self.y1 - self.y0)/2.0));
82                 context->line_to (intersect->x1, self.y0 + ((self.y1 - self.y0)/2.0));
83                 context->stroke ();
84         }
85 }
86
87 void
88 LineSet::add (Coord y, Distance width, Color color)
89 {
90         begin_change ();
91         
92         _lines.push_back (Line (y, width, color));
93         _lines.sort (LineSorter ());
94
95         _bounding_box_dirty = true;
96         end_change ();
97 }
98
99 void
100 LineSet::clear ()
101 {
102         begin_change ();
103         _lines.clear ();
104         _bounding_box_dirty = true;
105         end_change ();
106 }
107
108 bool
109 LineSet::covers (Duple const & /*point*/) const
110 {
111         return false;
112 }