Merge branch 'master' into ccmerge
[ardour.git] / libs / canvas / rectangle.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 <iostream>
21 #include <cairomm/context.h>
22 #include "pbd/stacktrace.h"
23 #include "pbd/compose.h"
24
25 #include "canvas/canvas.h"
26 #include "canvas/rectangle.h"
27 #include "canvas/debug.h"
28 #include "canvas/utils.h"
29
30 using namespace std;
31 using namespace ArdourCanvas;
32
33 Rectangle::Rectangle (Group* parent)
34         : Item (parent)
35         , Outline (parent)
36         , Fill (parent)
37         , _outline_what ((What) (LEFT | RIGHT | TOP | BOTTOM))
38 {
39
40 }
41
42 Rectangle::Rectangle (Group* parent, Rect const & rect)
43         : Item (parent)
44         , Outline (parent)
45         , Fill (parent)
46         , _rect (rect)
47         , _outline_what ((What) (LEFT | RIGHT | TOP | BOTTOM))
48 {
49         
50 }
51
52 void
53 Rectangle::render (Rect const & area, Cairo::RefPtr<Cairo::Context> context) const
54 {
55         Rect self = item_to_window (_rect);
56         boost::optional<Rect> d = self.intersection (area);
57
58         if (!d) {
59                 return;
60         }
61         
62         Rect draw = d.get();
63         static const double boundary = 0.5;
64         const double x_limit = _canvas->visible_area().width();
65
66         draw.x0 = max (self.x0, max (0.0, draw.x0 - boundary));
67         draw.x1 = min (self.x1, min (x_limit, draw.x1 + boundary));
68
69         draw.y0 = max (self.y0, max (0.0, draw.y0 - boundary));
70         draw.y1 = min (self.y1, min (x_limit, draw.y1 + boundary));
71
72         Rect fill_rect = draw;
73         Rect stroke_rect = fill_rect.expand (0.5);
74
75         if (_fill) {
76                 if (_stops.empty()) {
77                         setup_fill_context (context);
78                 } else {
79                         setup_gradient_context (context, self, Duple (draw.x0, draw.y0));
80                 }
81                 context->rectangle (fill_rect.x0, fill_rect.y0, fill_rect.width(), fill_rect.height());
82                 context->fill ();
83         }
84         
85         if (_outline) {
86
87                 setup_outline_context (context);
88
89                 if (_outline_what & LEFT) {
90                         context->move_to (stroke_rect.x0, stroke_rect.y0);
91                         context->line_to (stroke_rect.x0, stroke_rect.y1);
92                 }
93                 
94                 if (_outline_what & BOTTOM) {
95                         context->move_to (stroke_rect.x0, stroke_rect.y1);
96                         context->line_to (stroke_rect.x1, stroke_rect.y1);
97                 }
98                 
99                 if (_outline_what & RIGHT) {
100                         context->move_to (stroke_rect.x1, stroke_rect.y0);
101                         context->line_to (stroke_rect.x1, stroke_rect.y1);
102                 }
103                 
104                 if (_outline_what & TOP) {
105                         context->move_to (stroke_rect.x0, stroke_rect.y0);
106                         context->line_to (stroke_rect.x1, stroke_rect.y0);
107                 }
108                 
109                 context->stroke ();
110         }
111 }
112
113 void
114 Rectangle::compute_bounding_box () const
115 {
116         Rect r = _rect.fix ();
117         _bounding_box = boost::optional<Rect> (r.expand (_outline_width / 2));
118         
119         _bounding_box_dirty = false;
120 }
121
122 void
123 Rectangle::set (Rect const & r)
124 {
125         /* We don't update the bounding box here; it's just
126            as cheap to do it when asked.
127         */
128         
129         begin_change ();
130         
131         _rect = r;
132         
133         _bounding_box_dirty = true;
134         end_change ();
135
136         DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (set)\n");
137 }
138
139 void
140 Rectangle::set_x0 (Coord x0)
141 {
142         begin_change ();
143
144         _rect.x0 = x0;
145
146         _bounding_box_dirty = true;
147         end_change ();
148
149         DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (x0)\n");
150 }
151
152 void
153 Rectangle::set_y0 (Coord y0)
154 {
155         begin_change ();
156         
157         _rect.y0 = y0;
158
159         _bounding_box_dirty = true;
160         end_change();
161
162         DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (y0)\n");
163 }
164
165 void
166 Rectangle::set_x1 (Coord x1)
167 {
168         begin_change ();
169         
170         _rect.x1 = x1;
171
172         _bounding_box_dirty = true;
173         end_change ();
174
175         DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (x1)\n");
176 }
177
178 void
179 Rectangle::set_y1 (Coord y1)
180 {
181         begin_change ();
182
183         _rect.y1 = y1;
184
185         _bounding_box_dirty = true;
186         end_change ();
187
188         DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (y1)\n");
189 }
190
191 void
192 Rectangle::set_outline_what (What what)
193 {
194         begin_change ();
195         
196         _outline_what = what;
197
198         end_change ();
199 }
200
201 void
202 Rectangle::set_outline_what (int what)
203 {
204         set_outline_what ((What) what);
205 }
206