merge with master.
[ardour.git] / libs / canvas / arrow.cc
1 /*
2     Copyright (C) 2011 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
21 /** @file  canvas/arrow.cc
22  *  @brief Implementation of the Arrow canvas object.
23  */
24
25 #include "pbd/compose.h"
26
27 #include "canvas/arrow.h"
28 #include "canvas/debug.h"
29 #include "canvas/polygon.h"
30 #include "canvas/line.h"
31
32 using namespace ArdourCanvas;
33
34 /** Construct an Arrow.
35  *  @param parent Parent canvas group.
36  */
37 Arrow::Arrow (Canvas* c)
38         : Container (c)
39 {
40         setup ();
41 }
42
43 Arrow::Arrow (Item* parent)
44         : Container (parent)
45 {
46         setup ();
47 }
48
49 void
50 Arrow::setup ()
51 {
52         /* set up default arrow heads at each end */
53         for (int i = 0; i < 2; ++i) {
54                 _heads[i].polygon = new Polygon (this);
55                 _heads[i].outward = true;
56                 _heads[i].width = 4;
57                 _heads[i].height = 4;
58                 setup_polygon (i);
59                 CANVAS_DEBUG_NAME (_heads[i].polygon, string_compose ("arrow head %1", i));
60         }
61         
62         _line = new Line (this);
63         CANVAS_DEBUG_NAME (_line, "arrow line");
64 }
65
66
67 /** Set whether to show an arrow head at one end or other
68  *  of the line.
69  *  @param which 0 or 1 to specify the arrow head to set up.
70  *  @param true if this arrow head should be shown.
71  */
72 void
73 Arrow::set_show_head (int which, bool show)
74 {
75         assert (which == 0 || which == 1);
76         
77         begin_change ();
78         
79         if (!show) {
80                 delete _heads[which].polygon;
81                 _heads[which].polygon = 0;
82         } else {
83                 setup_polygon (which);
84         }
85
86         _bounding_box_dirty = true;
87         end_change ();
88 }
89
90 /** Set whether a given arrow head points into the line or
91  *  away from it.
92  *  @param which 0 or 1 to specify the arrow head to set up.
93  *  @param true if this arrow head should point out from the line,
94  *  otherwise false to point in.
95  */
96 void
97 Arrow::set_head_outward (int which, bool outward)
98 {
99         assert (which == 0 || which == 1);
100         
101         begin_change ();
102
103         _heads[which].outward = outward;
104
105         setup_polygon (which);
106         _bounding_box_dirty = true;
107         end_change ();
108 }
109
110 /** Set the height of a given arrow head.
111  *  @param which 0 or 1 to specify the arrow head to set up.
112  *  @param height Height of the arrow head in pixels.
113  */
114 void
115 Arrow::set_head_height (int which, Distance height)
116 {
117         assert (which == 0 || which == 1);
118         
119         begin_change ();
120         
121         _heads[which].height = height;
122
123         setup_polygon (which);
124         _bounding_box_dirty = true;
125         end_change ();
126 }
127
128 /** Set the width of a given arrow head.
129  *  @param which 0 or 1 to specify the arrow head to set up.
130  *  @param width Width of the arrow head in pixels.
131  */
132 void
133 Arrow::set_head_width (int which, Distance width)
134 {
135         assert (which == 0 || which == 1);
136         
137         begin_change ();
138         
139         _heads[which].width = width;
140
141         setup_polygon (which);
142         _bounding_box_dirty = true;
143         end_change ();
144 }
145
146 /** Set the width of our line, and the outline of our arrow(s).
147  *  @param width New width in pixels.
148  */
149 void
150 Arrow::set_outline_width (Distance width)
151 {
152         _line->set_outline_width (width);
153         if (_heads[0].polygon) {
154                 _heads[0].polygon->set_outline_width (width);
155         }
156         if (_heads[1].polygon) {
157                 _heads[1].polygon->set_outline_width (width);
158         }
159 }
160
161 /** Set the x position of our line.
162  *  @param x New x position in pixels (in our coordinate system).
163  */
164 void
165 Arrow::set_x (Coord x)
166 {
167         _line->set_x0 (x);
168         _line->set_x1 (x);
169         for (int i = 0; i < 2; ++i) {
170                 if (_heads[i].polygon) {
171                         _heads[i].polygon->set_x_position (x - _heads[i].width / 2);
172                 }
173         }
174                 
175 }
176
177 /** Set the y position of end 0 of our line.
178  *  @param y0 New y0 position in pixels (in our coordinate system).
179  */
180 void
181 Arrow::set_y0 (Coord y0)
182 {
183         _line->set_y0 (y0);
184         if (_heads[0].polygon) {
185                 _heads[0].polygon->set_y_position (y0);
186         }
187 }
188
189 /** Set the y position of end 1 of our line.
190  *  @param y1 New y1 position in pixels (in our coordinate system).
191  */
192 void
193 Arrow::set_y1 (Coord y1)
194 {
195         _line->set_y1 (y1);
196         if (_heads[1].polygon) {
197                 _heads[1].polygon->set_y_position (y1 - _heads[1].height);
198         }
199 }
200
201 /** @return x position of our line in pixels (in our coordinate system) */
202 Coord
203 Arrow::x () const
204 {
205         return _line->x0 ();
206 }
207
208 /** @return y position of end 1 of our line in pixels (in our coordinate system) */
209 Coord
210 Arrow::y1 () const
211 {
212         return _line->y1 ();
213 }
214
215 /** Set up the polygon used to represent a particular arrow head.
216  *  @param which 0 or 1 to specify the arrow head to set up.
217  */
218 void
219 Arrow::setup_polygon (int which)
220 {
221         assert (which == 0 || which == 1);
222         
223         Points points;
224
225         if ((which == 0 && _heads[which].outward) || (which == 1 && !_heads[which].outward)) {
226                 /* this is an arrow head pointing towards -ve y */
227                 points.push_back (Duple (_heads[which].width / 2, 0));
228                 points.push_back (Duple (_heads[which].width, _heads[which].height));
229                 points.push_back (Duple (0, _heads[which].height));
230         } else {
231                 /* this is an arrow head pointing towards +ve y */
232                 points.push_back (Duple (0, 0));
233                 points.push_back (Duple (_heads[which].width, 0));
234                 points.push_back (Duple (_heads[which].width / 2, _heads[which].height));
235                 points.push_back (Duple (0, 0));
236         }
237
238         _heads[which].polygon->set (points);
239 }
240
241 /** Set the color of our line and arrow heads.
242  *  @param color New color.
243  */
244 void
245 Arrow::set_color (Color color)
246 {
247         _line->set_outline_color (color);
248         for (int i = 0; i < 2; ++i) {
249                 if (_heads[i].polygon) {
250                         _heads[i].polygon->set_outline_color (color);
251                         _heads[i].polygon->set_fill_color (color);
252                 }
253         }
254 }
255
256 bool
257 Arrow::covers (Duple const & point) const
258 {
259         if (_heads[0].polygon && _heads[0].polygon->covers (point)) {
260                 return true;
261         }
262         if (_line && _line->covers (point)) {
263                 return true;
264         }
265
266         if (_heads[1].polygon && _heads[1].polygon->covers (point)) {
267                 return true;
268         }
269
270         return false;
271 }