fix redrawing of canvas with an optimized build
[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> r = self.intersection (area);
57
58         if (!r) {
59                 std::cerr << whatami() << '/' << name << " not covered by render area! ... " << self << " vs. " << area << std::endl;
60                 return;
61         }
62
63         Rect draw = r.get ();
64
65         if (_fill) {
66                 if (_stops.empty()) {
67                         setup_fill_context (context);
68                 } else {
69                         setup_gradient_context (context, self, Duple (draw.x0, draw.y0));
70                 }
71                 context->rectangle (draw.x0, draw.y0, draw.width(), draw.height());
72                 context->fill ();
73         }
74         
75         if (_outline) {
76
77                 setup_outline_context (context);
78
79                 context->save ();
80                 context->rectangle (draw.x0, draw.y0, draw.width(), draw.height());
81                 context->clip ();
82
83                 if (_outline_what & LEFT) {
84                         context->move_to (self.x0, self.y0);
85                         context->line_to (self.x0, self.y1);
86                 }
87                 
88                 if (_outline_what & BOTTOM) {
89                         context->move_to (self.x0, self.y1);
90                         context->line_to (self.x1, self.y1);
91                 }
92                 
93                 if (_outline_what & RIGHT) {
94                         context->move_to (self.x1, self.y0);
95                         context->line_to (self.x1, self.y1);
96                 }
97                 
98                 if (_outline_what & TOP) {
99                         context->move_to (self.x0, self.y0);
100                         context->line_to (self.x1, self.y0);
101                 }
102                 
103                 context->stroke ();
104                 context->restore ();
105         }
106 }
107
108 void
109 Rectangle::compute_bounding_box () const
110 {
111         Rect r = _rect.fix ();
112         _bounding_box = boost::optional<Rect> (r.expand (_outline_width/2.0));
113         _bounding_box_dirty = false;
114 }
115
116 void
117 Rectangle::set (Rect const & r)
118 {
119         /* We don't update the bounding box here; it's just
120            as cheap to do it when asked.
121         */
122         
123         begin_change ();
124         
125         _rect = r;
126         
127         _bounding_box_dirty = true;
128         end_change ();
129
130         DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (set)\n");
131 }
132
133 void
134 Rectangle::set_x0 (Coord x0)
135 {
136         begin_change ();
137
138         _rect.x0 = x0;
139
140         _bounding_box_dirty = true;
141         end_change ();
142
143         DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (x0)\n");
144 }
145
146 void
147 Rectangle::set_y0 (Coord y0)
148 {
149         begin_change ();
150         
151         _rect.y0 = y0;
152
153         _bounding_box_dirty = true;
154         end_change();
155
156         DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (y0)\n");
157 }
158
159 void
160 Rectangle::set_x1 (Coord x1)
161 {
162         begin_change ();
163         
164         _rect.x1 = x1;
165
166         _bounding_box_dirty = true;
167         end_change ();
168
169         DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (x1)\n");
170 }
171
172 void
173 Rectangle::set_y1 (Coord y1)
174 {
175         begin_change ();
176
177         _rect.y1 = y1;
178
179         _bounding_box_dirty = true;
180         end_change ();
181
182         DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (y1)\n");
183 }
184
185 void
186 Rectangle::set_outline_what (What what)
187 {
188         begin_change ();
189         
190         _outline_what = what;
191
192         end_change ();
193 }
194
195 void
196 Rectangle::set_outline_what (int what)
197 {
198         set_outline_what ((What) what);
199 }
200