249106de33fe748578d1f9555bbfc5df1927a361
[ardour.git] / libs / canvas / rectangle.cc
1 #include <iostream>
2 #include <cairomm/context.h>
3 #include "pbd/stacktrace.h"
4 #include "pbd/xml++.h"
5 #include "pbd/compose.h"
6 #include "canvas/rectangle.h"
7 #include "canvas/debug.h"
8 #include "canvas/utils.h"
9
10 using namespace std;
11 using namespace ArdourCanvas;
12
13 Rectangle::Rectangle (Group* parent)
14         : Item (parent)
15         , Outline (parent)
16         , Fill (parent)
17         , _outline_what ((What) (LEFT | RIGHT | TOP | BOTTOM))
18 {
19
20 }
21
22 Rectangle::Rectangle (Group* parent, Rect const & rect)
23         : Item (parent)
24         , Outline (parent)
25         , Fill (parent)
26         , _rect (rect)
27         , _outline_what ((What) (LEFT | RIGHT | TOP | BOTTOM))
28 {
29         
30 }
31
32 void
33 Rectangle::render (Rect const & /*area*/, Cairo::RefPtr<Cairo::Context> context) const
34 {
35         Rect plot = _rect;
36
37         plot.x1 = min (plot.x1, CAIRO_MAX);
38         plot.y1 = min (plot.y1, CAIRO_MAX);
39
40         if (_fill) {
41                 setup_fill_context (context);
42                 context->rectangle (plot.x0, plot.y0, plot.width(), plot.height());
43                 
44                 if (!_outline) {
45                         context->fill ();
46                 } else {
47                         
48                         /* special/common case: outline the entire rectangle is
49                          * requested, so just use the same path for the fill
50                          * and stroke.
51                          */
52
53                         if (_outline_what == What (LEFT|RIGHT|BOTTOM|TOP)) {
54                                 context->fill_preserve();
55                                 setup_outline_context (context);
56                                 context->stroke ();
57                         } else {
58                                 context->fill ();
59                         }
60                 }
61         } 
62         
63         if (_outline) {
64                 
65                 if (_outline_what == What (LEFT|RIGHT|BOTTOM|TOP)) {
66
67                         /* if we filled and use full outline, we are already done */
68
69                         if (!_fill) { 
70                                 context->rectangle (plot.x0, plot.y0, plot.width(), plot.height());
71                                 setup_outline_context (context);
72                                 context->stroke ();
73                         }
74                         
75                 } else {
76                         
77                         if (_outline_what & LEFT) {
78                                 context->move_to (plot.x0, plot.y0);
79                                 context->line_to (plot.x0, plot.y1);
80                         }
81                         
82                         if (_outline_what & BOTTOM) {
83                                 context->move_to (plot.x0, plot.y1);
84                                 context->line_to (plot.x1, plot.y1);
85                         }
86                         
87                         if (_outline_what & RIGHT) {
88                                 context->move_to (plot.x1, plot.y0);
89                                 context->line_to (plot.x1, plot.y1);
90                         }
91                         
92                         if (_outline_what & TOP) {
93                                 context->move_to (plot.x0, plot.y0);
94                                 context->line_to (plot.x1, plot.y0);
95                         }
96                         
97                         setup_outline_context (context);
98                         context->stroke ();
99                 }
100         }
101 }
102
103 void
104 Rectangle::compute_bounding_box () const
105 {
106         Rect r = _rect.fix ();
107         _bounding_box = boost::optional<Rect> (r.expand (_outline_width / 2));
108         
109         _bounding_box_dirty = false;
110 }
111
112 void
113 Rectangle::set (Rect const & r)
114 {
115         /* We don't update the bounding box here; it's just
116            as cheap to do it when asked.
117         */
118         
119         begin_change ();
120         
121         _rect = r;
122         
123         _bounding_box_dirty = true;
124         end_change ();
125
126         DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (set)\n");
127 }
128
129 void
130 Rectangle::set_x0 (Coord x0)
131 {
132         begin_change ();
133
134         _rect.x0 = x0;
135
136         _bounding_box_dirty = true;
137         end_change ();
138
139         DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (x0)\n");
140 }
141
142 void
143 Rectangle::set_y0 (Coord y0)
144 {
145         begin_change ();
146         
147         _rect.y0 = y0;
148
149         _bounding_box_dirty = true;
150         end_change();
151
152         DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (y0)\n");
153 }
154
155 void
156 Rectangle::set_x1 (Coord x1)
157 {
158         begin_change ();
159         
160         _rect.x1 = x1;
161
162         _bounding_box_dirty = true;
163         end_change ();
164
165         DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (x1)\n");
166 }
167
168 void
169 Rectangle::set_y1 (Coord y1)
170 {
171         begin_change ();
172
173         _rect.y1 = y1;
174
175         _bounding_box_dirty = true;
176         end_change ();
177
178         DEBUG_TRACE (PBD::DEBUG::CanvasItemsDirtied, "canvas item dirty: rectangle change (y1)\n");
179 }
180
181 void
182 Rectangle::set_outline_what (What what)
183 {
184         begin_change ();
185         
186         _outline_what = what;
187
188         end_change ();
189 }
190
191 void
192 Rectangle::set_outline_what (int what)
193 {
194         set_outline_what ((What) what);
195 }
196