root/gui/flowcanvas/Connection.cpp @ 67cc9c9e05d47e6074167fc05c12ec87e8c0058e

Revision 67cc9c9e05d47e6074167fc05c12ec87e8c0058e, 8.6 KB (checked in by Nedko Arnaudov <nedko@…>, 15 months ago)

embed flowcanvas-0.7.1

  • Property mode set to 100644
Line 
1/* This file is part of FlowCanvas.
2 * Copyright (C) 2007-2009 David Robillard <http://drobilla.net>
3 *
4 * FlowCanvas is free software; you can redistribute it and/or modify it under the
5 * terms of the GNU General Public License as published by the Free Software
6 * Foundation; either version 2 of the License, or (at your option) any later
7 * version.
8 *
9 * FlowCanvas is distributed in the hope that it will be useful, but WITHOUT ANY
10 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
16 */
17
18#include <algorithm>
19#include <cassert>
20#include <cmath>
21#include <string>
22
23#include <libgnomecanvasmm.h>
24
25#include "Canvas.hpp"
26#include "Connectable.hpp"
27#include "Connection.hpp"
28#include "Ellipse.hpp"
29
30namespace FlowCanvas {
31
32
33Connection::Connection(boost::shared_ptr<Canvas>      canvas,
34                           boost::shared_ptr<Connectable> source,
35                           boost::shared_ptr<Connectable> dest,
36                       uint32_t                       color,
37                       bool                           show_arrowhead)
38        : Gnome::Canvas::Group(*canvas->root())
39        , _canvas(canvas)
40        , _source(source)
41        , _dest(dest)
42        , _bpath(*this)
43        , _path(gnome_canvas_path_def_new())
44        , _handle(NULL)
45        , _color(color)
46        , _handle_style(HANDLE_NONE)
47        , _selected(false)
48        , _show_arrowhead(show_arrowhead)
49{
50        _bpath.property_width_units() = 2.0;
51        set_color(color);
52
53        update_location();
54        raise_to_top();
55}
56
57
58Connection::~Connection()
59{
60        gnome_canvas_path_def_unref(_path);
61}
62
63
64void
65Connection::set_color(uint32_t color)
66{
67        _color = color;
68        _bpath.property_outline_color_rgba() = _color;
69        if (_handle) {
70                if (_handle->text) {
71                        _handle->text->property_fill_color_rgba() = _color;
72                }
73                if (_handle->shape) {
74                        _handle->shape->property_fill_color_rgba() = 0x000000FF;
75                        _handle->shape->property_outline_color_rgba() = _color;
76                }
77        }
78}
79
80
81/** Updates the path of the connection to match it's ports if they've moved.
82 */
83void
84Connection::update_location()
85{
86        boost::shared_ptr<Connectable> src = _source.lock();
87        boost::shared_ptr<Connectable> dst = _dest.lock();
88
89        if (!src || !dst)
90                return;
91
92        bool straight = (boost::dynamic_pointer_cast<Ellipse>(src)
93                      || boost::dynamic_pointer_cast<Ellipse>(dst));
94
95        const Gnome::Art::Point src_point = src->src_connection_point();
96        const Gnome::Art::Point dst_point = dst->dst_connection_point(src_point);
97
98        const double src_x = src_point.get_x();
99        const double src_y = src_point.get_y();
100        const double dst_x = dst_point.get_x();
101        const double dst_y = dst_point.get_y();
102
103        if (straight) {
104
105                gnome_canvas_path_def_reset(_path);
106                gnome_canvas_path_def_moveto(_path, src_x, src_y);
107                gnome_canvas_path_def_lineto(_path, dst_x, dst_y);
108                double dx = src_x - dst_x;
109                double dy = src_y - dst_y;
110
111                if (_handle) {
112                        _handle->property_x() = src_x - dx/2.0;
113                        _handle->property_y() = src_y - dy/2.0;
114                        _handle->move(0, 0);
115                }
116
117                if (_show_arrowhead) {
118
119                        const double h  = sqrt(dx*dx + dy*dy);
120
121                        dx = dx / h * 10;
122                        dy = dy / h * 10;
123
124                        gnome_canvas_path_def_lineto(_path,
125                                        dst_x + dx - dy/1.5,
126                                        dst_y + dy + dx/1.5);
127
128                        gnome_canvas_path_def_moveto(_path, dst_x, dst_y);
129
130                        gnome_canvas_path_def_lineto(_path,
131                                        dst_x + dx + dy/1.5,
132                                        dst_y + dy - dx/1.5);
133                }
134
135        } else {
136
137                const double join_x = (src_x + dst_x)/2.0;
138                const double join_y = (src_y + dst_y)/2.0;
139
140                double dx = fabs(dst_x - src_x);
141                double dy = fabs(dst_y - src_y);
142
143                Gnome::Art::Point src_vec = src->connection_point_vector(dx/3.0, dy/3.0);
144                Gnome::Art::Point dst_vec = dst->connection_point_vector(dx/3.0, dy/3.0);
145
146                double src_point_dx = src_vec.get_x();
147                double src_point_dy = src_vec.get_y();
148                double dst_point_dx = dst_vec.get_x();
149                double dst_point_dy = dst_vec.get_y();
150
151                // Path 1 (src_x, src_y) -> (join_x, join_y)
152                // Control point 1
153                const double src_x1 = src_x + src_point_dx;
154                const double src_y1 = src_y + src_point_dy;
155                // Control point 2
156                const double src_x2 = (join_x + src_x1) / 2.0;
157                const double src_y2 = (join_y + src_y1) / 2.0;
158
159                // Path 2, (join_x, join_y) -> (dst_x, dst_y)
160                // Control point 1
161                const double dst_x1 = dst_x - dst_point_dx;
162                const double dst_y1 = dst_y - dst_point_dy;
163                // Control point 2
164                const double dst_x2 = (join_x + dst_x1) / 2.0;
165                const double dst_y2 = (join_y + dst_y1) / 2.0;
166
167                // libgnomecanvasmm + GTK 2.8 screwed up the Path API; use the C one.
168                gnome_canvas_path_def_reset(_path);
169                gnome_canvas_path_def_moveto(_path, src_x, src_y);
170                gnome_canvas_path_def_curveto(_path, src_x1, src_y1, src_x2, src_y2, join_x, join_y);
171                gnome_canvas_path_def_curveto(_path, dst_x2, dst_y2, dst_x1, dst_y1, dst_x, dst_y);
172
173                // Uncomment to see control point path as straight lines
174                /*gnome_canvas_path_def_reset(_path);
175                gnome_canvas_path_def_moveto(_path, src_x, src_y);
176                gnome_canvas_path_def_lineto(_path, src_x1, src_y1);
177                gnome_canvas_path_def_lineto(_path, src_x2, src_y2);
178                gnome_canvas_path_def_lineto(_path, join_x, join_y);
179                gnome_canvas_path_def_lineto(_path, dst_x2, dst_y2);
180                gnome_canvas_path_def_lineto(_path, dst_x1, dst_y1);
181                gnome_canvas_path_def_lineto(_path, dst_x, dst_y);*/
182
183                if (_show_arrowhead) {
184
185                        const double h  = sqrt(dx*dx + dy*dy);
186
187                        dx = dx / h * 10;
188                        dy = dy / h * 10;
189
190                        gnome_canvas_path_def_lineto(_path,
191                                        dst_x - 12,
192                                        dst_y - 4);
193
194                        gnome_canvas_path_def_moveto(_path, dst_x, dst_y);
195
196                        gnome_canvas_path_def_lineto(_path,
197                                        dst_x - 12,
198                                        dst_y + 4);
199                }
200        }
201
202        GnomeCanvasBpath* c_obj = _bpath.gobj();
203        gnome_canvas_item_set(GNOME_CANVAS_ITEM(c_obj), "bpath", _path, NULL);
204}
205
206
207/** Set label text displayed next to the edge.
208 *
209 * Passing the empty string will remove the label.
210 */
211void
212Connection::set_label(const std::string& str)
213{
214        if (str != "") {
215                if (!_handle)
216                        _handle = new Handle(*this);
217
218                if (!_handle->text) {
219                        _handle->text = new Gnome::Canvas::Text(*_handle, 0, 0, str);
220                        _handle->text->property_size_set() = true;
221                        _handle->text->property_size() = 9000;
222                        _handle->text->property_weight_set() = true;
223                        _handle->text->property_weight() = 200;
224                        _handle->text->property_fill_color_rgba() = _color;
225                        _handle->text->show();
226                } else {
227                        _handle->text->property_text() = str;
228                }
229
230                if (_handle->shape)
231                        show_handle(true);
232
233                _handle->text->raise(1);
234                update_location();
235        } else if (_handle) {
236                delete _handle->text;
237                _handle->text = NULL;
238        }
239}
240
241
242void
243Connection::show_handle(bool show)
244{
245        if (show) {
246                if (!_handle)
247                        _handle = new Handle(*this);
248
249                double handle_width = 8.0;
250                double handle_height = 8.0;
251                if (_handle->text) {
252                        handle_width = _handle->text->property_text_width();
253                        handle_height = _handle->text->property_text_height();
254                }
255
256                // FIXME: slow
257                delete _handle->shape;
258
259                if (_handle_style != HANDLE_NONE) {
260                        if (_handle_style == HANDLE_RECT)
261                                _handle->shape = new Gnome::Canvas::Rect(*_handle,
262                                                -handle_width/2.0 - 1.0, -handle_height/2.0,
263                                                handle_width/2.0 + 1.0, handle_height/2.0);
264                        else// if (_handle_style == HANDLE_CIRCLE)
265                                _handle->shape = new Gnome::Canvas::Ellipse(*_handle,
266                                                -handle_width/2.0 - 1.0, -handle_height/2.0,
267                                                handle_width/2.0 + 1.0, handle_height/2.0);
268                }
269
270                _handle->shape->property_fill_color_rgba() = 0x000000FF;
271                _handle->shape->property_outline_color_rgba() = _color;
272                _handle->shape->show();
273                _handle->show();
274
275        } else {
276                delete _handle;
277                _handle = NULL;
278        }
279}
280
281
282void
283Connection::set_highlighted(bool b)
284{
285        if (b)
286                _bpath.property_outline_color_rgba() = 0xFF0000FF;
287        else
288                _bpath.property_outline_color_rgba() = _color;
289}
290
291
292void
293Connection::set_selected(bool selected)
294{
295        _selected = selected;
296
297        if (selected) {
298                _bpath.property_dash() = _canvas.lock()->select_dash();
299        } else {
300                _bpath.property_dash() = NULL;
301        }
302}
303
304
305/** Overloaded Gnome::Canvas::Item::raise_to_top to ensure src and dst
306 * are still above connections (to hide the part behind connected Ellipses).
307 */
308void
309Connection::raise_to_top()
310{
311        Gnome::Canvas::Item::raise_to_top();
312
313        // Raise source above us
314        boost::shared_ptr<Item> item = boost::dynamic_pointer_cast<Item>(_source.lock());
315        if (item)
316                item->raise_to_top();
317
318        // Raise dest above us
319        item = boost::dynamic_pointer_cast<Item>(_dest.lock());
320        if (item)
321                item->raise_to_top();
322
323        /* Raise the roof
324               \o/
325                |
326               / \
327        */
328}
329
330
331void
332Connection::select_tick()
333{
334        _bpath.property_dash() = _canvas.lock()->select_dash();
335}
336
337
338void
339Connection::zoom(double z)
340{
341        if (_handle && _handle->text) {
342                _handle->text->property_size() = static_cast<int>(floor((double)9000.0f * z));
343        }
344}
345
346
347} // namespace FlowCanvas
348
Note: See TracBrowser for help on using the browser.