Developer Documentation

connection.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41
42
43
44 //== INCLUDES =================================================================
45 #include <QGraphicsSceneMouseEvent>
46 #include <QGraphicsScene>
47
48 #include "elementInOut.hh"
49 #include "elementInput.hh"
50 #include "elementOutput.hh"
51 #include "connection.hh"
52 #include "connectionPoint.hh"
53 #include "graphicsScene.hh"
54 #include "elementArea.hh"
55 #include "wayfind.hh"
56
57 //== NAMESPACES ===============================================================
58 namespace VSI {
59
60 //=============================================================================
61 //
62 // CLASS VSI::Connection - IMPLEMENTATION
63 //
64 //=============================================================================
65
67 Connection::Connection (ConnectionPoint *_start, QGraphicsScene *_scene) :
68 QGraphicsPathItem (dynamic_cast<GraphicsScene *>(_scene)->elementArea ()),
69 scene_ (dynamic_cast<GraphicsScene *>(_scene)),
70 p1_ (_start),
71 p2_ (0),
72 old_ (0)
73 {
74
75 elementArea_ = scene_->elementArea ();
76
77 QPen p = pen ();
78
79 p.setCapStyle (Qt::RoundCap);
80 p.setColor (QColor (128, 128, 128));
81
82 if (p1_->inOut ()->inOut ()->typeString () == "data")
83 p.setWidth (4);
84 else
85 p.setWidth (2);
86 setPen (p);
87 }
88
90 Connection::Connection (ConnectionPoint *_start, ConnectionPoint *_end, QGraphicsScene *_scene) :
91 QGraphicsPathItem (dynamic_cast<GraphicsScene *>(_scene)->elementArea ()),
92 scene_ (dynamic_cast<GraphicsScene *>(_scene)),
93 p1_ (_start),
94 p2_ (_end)
95 {
96 elementArea_ = scene_->elementArea ();
97
98 QPen p = pen ();
99
100 p.setCapStyle (Qt::RoundCap);
101
102 if (p1_->inOut ()->inOut ()->typeString () == "data")
103 p.setWidth (4);
104 else
105 p.setWidth (2);
106 setPen (p);
107
108 if (!p1_->inOut ()->validConnection (p2_->inOut ()))
109 {
110 deleteLater ();
111 p1_ = p2_ = 0;
112 return;
113 }
114
115 way_ = QPolygonF ();
116
117 p.setColor (QColor (0, 0, 0));
118 setPen (p);
119
120 p1_->inOut ()->addConnection (this);
121 p2_->inOut ()->addConnection (this);
122 }
123
125 Connection::~Connection ()
126 {
127 if (p1_)
128 p1_->inOut ()->removeConnection (this);
129 if (p2_)
130 p2_->inOut ()->removeConnection (this);
131 }
132
133 // handle mouse movement
134 void Connection::mouseMoveEvent (QGraphicsSceneMouseEvent *_event)
135 {
136 QPen p = pen ();
137
138 ConnectionPoint *pnt = cPointAt (_event->scenePos ());
139
140 if (pnt)
141 { if (p1_->inOut ()->validConnection (pnt->inOut ()))
142 p.setColor (QColor (0, 255, 0));
143 else
144 p.setColor (QColor (255, 0, 0));
145 }
146 else
147 p.setColor (QColor (128, 128, 128));
148 setPen (p);
149
150 way_ = scene_->wayFind ()->findWay (this, p1_->connectPos ().toPoint (), elementArea_->mapFromScene (_event->scenePos ()).toPoint ());
151 updateLine ();
152 }
153
154 // Start new connection on mouse press
155 void Connection::mousePressEvent (QGraphicsSceneMouseEvent *_event)
156 {
157 if (p1_)
158 p1_->inOut ()->removeConnection (this);
159 if (p2_)
160 p2_->inOut ()->removeConnection (this);
161
162 QPointF p = p1_->connectPos () - _event->scenePos ();
163 qreal d1 = (p.x () * p.x()) + (p.y () * p.y ());
164 p = p2_->connectPos () - _event->scenePos ();
165 qreal d2 = (p.x () * p.x()) + (p.y () * p.y ());
166
167 if (d2 > d1)
168 {
169 old_ = p1_;
170 p1_ = p2_;
171 }
172
173 way_ = scene_->wayFind ()->findWay (this, p1_->connectPos ().toPoint (), elementArea_->mapFromScene (_event->scenePos ()).toPoint ());
174 updateLine ();
175 }
176
177 // make a connection on relase at a valid connection point
178 void Connection::mouseReleaseEvent (QGraphicsSceneMouseEvent *_event)
179 {
180 scene_->setActiveConnection (0);
181
182 p2_ = cPointAt (_event->scenePos ());
183
184 if (!p2_ || !p1_->inOut ()->validConnection (p2_->inOut ()))
185 {
186 if (old_)
187 scene_->contentChange ();
188
189 deleteLater ();
190 p1_ = p2_ = 0;
191 return;
192 }
193
194 way_ = scene_->wayFind ()->findWay (this, p1_->connectPos ().toPoint (), p2_->connectPos ().toPoint ());
195 updateLine ();
196
197 QPen p = pen ();
198
199 p.setColor (QColor (0, 0, 0));
200 setPen (p);
201
202 if (old_ != p2_)
203 scene_->contentChange ();
204
205 old_ = p2_;
206
207 p1_->inOut ()->addConnection (this);
208 p2_->inOut ()->addConnection (this);
209
210 }
211
212 // helper to localize a connection point
213 ConnectionPoint *Connection::cPointAt (QPointF _pnt)
214 {
215
216 ConnectionPoint *pnt = 0;
217
218 foreach (QGraphicsItem *i, scene ()->items (_pnt))
219 {
220 ConnectionPoint *pt = dynamic_cast<ConnectionPoint *>(i);
221
222 if (pt)
223 {
224 pnt = pt;
225 }
226 }
227
228 return pnt;
229 }
230
232 void Connection::updatePositions ()
233 {
234 way_ = scene_->wayFind ()->findWay (this, p1_->connectPos ().toPoint (), p2_->connectPos ().toPoint ());
235 updateLine ();
236 }
237
239 ElementInput *Connection::input ()
240 {
241 ElementInput *i = dynamic_cast<ElementInput *> (p1_->inOut ());
242 if (!i)
243 i = dynamic_cast<ElementInput *> (p2_->inOut ());
244 return i;
245 }
246
248 ElementOutput *Connection::output ()
249 {
250 ElementOutput *o = dynamic_cast<ElementOutput *> (p1_->inOut ());
251 if (!o && p2_)
252 o = dynamic_cast<ElementOutput *> (p2_->inOut ());
253 return o;
254 }
255
257 const QPolygonF & VSI::Connection::way () const
258 {
259 return way_;
260 }
261
263 void Connection::invalidate()
264 {
265 way_ = QPolygonF ();
266 setPath (QPainterPath ());
267 }
268
269 // generates a curved line out of the way polygon
270 void Connection::updateLine()
271 {
272 QPainterPath path;
273
274 if (way_.size () <= 1)
275 {
276 setPath (path);
277 return;
278 }
279 else if (way_.size () == 2)
280 {
281 path.addPolygon(way_);
282 setPath (path);
283 return;
284 }
285
286 path.moveTo (way_[0]);
287
288 QPointF a,b,c;
289
290 for (int i = 2; i < way_.size (); i++)
291 {
292 a = way_[i-2];
293 b = way_[i-1];
294 c = way_[i];
295
296 QLineF l1 (a,b), l2 (b,c);
297
298 int rad = qMin (40.0, qMin (l1.length() / 2, l2.length() / 2));
299
300 if (rad > 5)
301 rad -= rad % 5;
302
303 if (a.x () == b.x ())
304 {
305 if (a.y () > b.y ())
306 {
307 path.lineTo (b.x (), b.y () + rad);
308 if (c.x () > b.x ())
309 {
310 path.arcTo (b.x (), b.y (), 2 * rad, 2 * rad, 180, -90);
311 }
312 else
313 {
314 path.arcTo (b.x () - (rad * 2), b.y (), 2 * rad, 2 * rad, 0, 90);
315 }
316 }
317 else
318 {
319 path.lineTo (b.x (), b.y () - rad);
320 if (c.x () > b.x ())
321 {
322 path.arcTo (b.x (), b.y () - (rad * 2), 2 * rad, 2 * rad, 180, 90);
323 }
324 else
325 {
326 path.arcTo (b.x () - (rad * 2), b.y () - (rad * 2), 2 * rad, 2 * rad, 0, -90);
327 }
328 }
329 }
330 else
331 {
332 if (a.x () > b.x ())
333 {
334 path.lineTo (b.x () + rad, b.y ());
335 if (c.y () > b.y ())
336 {
337 path.arcTo (b.x (), b.y (), 2 * rad, 2 * rad, 90, 90);
338 }
339 else
340 {
341 path.arcTo (b.x (), b.y () - (rad * 2), 2 * rad, 2 * rad, 270, -90);
342 }
343 }
344 else
345 {
346 path.lineTo (b.x () - rad, b.y ());
347 if (c.y () > b.y ())
348 {
349 path.arcTo (b.x () - (rad * 2), b.y (), 2 * rad, 2 * rad, 90, -90);
350 }
351 else
352 {
353 path.arcTo (b.x () - (rad * 2), b.y () - (rad * 2), 2 * rad, 2 * rad, 270, 90);
354 }
355 }
356 }
357 }
358
359 path.lineTo (c);
360
361 setPath (path);
362 }
363
364 }
VSI::GraphicsScene::wayFind
WayFind * wayFind()
WayFind object.
Definition: graphicsScene.hh:132
VSI::GraphicsScene::contentChange
void contentChange()
handle content changes
Definition: graphicsScene.cc:1107
VSI::ElementInOut::removeConnection
virtual void removeConnection(Connection *_conn)
Remove the Connection.
Definition: elementInOut.cc:164
VSI::ConnectionPoint::inOut
ElementInOut * inOut() const
Input/output element.
Definition: connectionPoint.hh:91
VSI::GraphicsScene::elementArea
ElementArea * elementArea() const
Element area.
Definition: graphicsScene.hh:123
VSI::Connection::output
ElementOutput * output()
Output of this connection.
Definition: connection.cc:248
VSI::Connection::updatePositions
void updatePositions()
called to update position on element movement
Definition: connection.cc:232
VSI::InOut::typeString
QString typeString() const
Type.
Definition: inout.cc:65
VSI::Connection::~Connection
~Connection()
Destructor.
Definition: connection.cc:125
VSI::ElementInOut::validConnection
bool validConnection(ElementInOut *_e)
Can this input/output be connected to _e.
Definition: elementInOut.cc:121
VSI::ConnectionPoint
Definition: connectionPoint.hh:67
VSI::ElementOutput
Definition: elementOutput.hh:60
VSI
Definition: baseWidget.cc:72
VSI::Connection::invalidate
void invalidate()
invalidate way
Definition: connection.cc:263
VSI::Connection::input
ElementInput * input()
Input of this connection.
Definition: connection.cc:239
VSI::Connection::way
const QPolygonF & way() const
way of the connection
Definition: connection.cc:257
VSI::ElementInOut::addConnection
virtual void addConnection(Connection *_conn)
Add the connection.
Definition: elementInOut.cc:156
VSI::GraphicsScene
Definition: graphicsScene.hh:80
VSI::ElementInOut::inOut
InOut * inOut() const
InOut context object.
Definition: elementInOut.hh:110
VSI::Connection::Connection
Connection(ConnectionPoint *_start, QGraphicsScene *_scene)
Constructor.
Definition: connection.cc:67
VSI::ElementInput
Definition: elementInput.hh:67
VSI::GraphicsScene::setActiveConnection
void setActiveConnection(Connection *_conn)
Sets the active connection.
Definition: graphicsScene.hh:144
VSI::WayFind::findWay
QPolygonF findWay(Connection *_conn, QPoint _from, QPoint _to)
Finds a way from _from to _to ignoring any already existent connections from _conn.
Definition: wayfind.cc:95
VSI::ConnectionPoint::connectPos
QPointF connectPos()
Position for connections.
Definition: connectionPoint.cc:141