Salome HOME
- add new method for view
[modules/geom.git] / src / DependencyTree / DependencyTree_Arrow.cxx
1 // Copyright (C) 2014  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "DependencyTree_Arrow.h"
21 #include "DependencyTree_Object.h"
22
23 // GUI includes
24 #include <SUIT_Session.h>
25 #include <SUIT_ResourceMgr.h>
26
27 // Qt includes
28 #include <QPainter>
29
30 #include <math.h>
31
32 const qreal arrowSize = 20;
33
34 DependencyTree_Arrow::DependencyTree_Arrow( DependencyTree_Object* theStartItem,
35                                             DependencyTree_Object* theEndItem,
36                                             QGraphicsItem* parent, QGraphicsScene* scene )
37 :QGraphicsLineItem( parent, scene ),
38 myIsBiLink( false ),
39 myStartItem( theStartItem ),
40 myEndItem( theEndItem )
41 {
42   SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
43
44   myColor = resMgr->colorValue( "Geometry", "dependency_tree_arrow_color", QColor( 0, 0, 130 ) );
45   myHighlightColor = resMgr->colorValue( "Geometry", "dependency_tree_highlight_arrow_color", QColor( 0, 0, 255 ) );
46   mySelectColor = resMgr->colorValue( "Geometry", "dependency_tree_select_arrow_color", QColor( 255, 0, 0 ) );
47
48   myStartItem = theStartItem;
49   myEndItem = theEndItem;
50
51   myLine = QLineF( myStartItem->pos(), myEndItem->pos() );
52   myArrowHead  = createArrowHead( myStartItem->pos(), myEndItem->pos() );
53   myReverseArrowHead = createArrowHead( myEndItem->pos(), myStartItem->pos() );
54
55   mySelfDependencyArrow = QRectF();
56
57   setPen( QPen( myColor, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin ) );
58   setColor( myColor );
59
60   setFlag( QGraphicsItem::ItemIsSelectable, true );
61   setZValue( -1000.0 );
62 }
63
64 DependencyTree_Arrow::~DependencyTree_Arrow()
65 {
66 }
67
68 //=================================================================================
69 // function : boundingRect()
70 // purpose  : return the outer bounds of the item as a rectangle.
71 //            QGraphicsView uses this to determine whether the item requires redrawing
72 //=================================================================================
73 QRectF DependencyTree_Arrow::boundingRect() const
74 {
75   qreal extra;
76   QRectF boundingRect;
77   if( myStartItem == myEndItem ) {
78     extra = arrowSize / 2.0;
79     boundingRect = mySelfDependencyArrow;
80   }
81   else {
82     extra = ( pen().width() + 20 ) / 2.0;
83     boundingRect = QRectF( myLine.p1(), QSizeF( myLine.p2().x() - myLine.p1().x(),
84                                                 myLine.p2().y() - myLine.p1().y() ) );
85   }
86   return boundingRect.normalized().adjusted( -extra, -extra, extra, extra );
87 }
88
89 //=================================================================================
90 // function : shape()
91 // purpose  : return the shape of this item to define an area of preselection
92 //=================================================================================
93 QPainterPath DependencyTree_Arrow::shape() const
94 {
95   QPainterPath path;
96
97   if( myStartItem == myEndItem ) {
98     qreal extra = 5;
99     QPolygonF aPolygonBigger( mySelfDependencyArrow.normalized()
100               .adjusted( -extra, -extra, extra, extra ) );
101     QPolygonF aPolygonSmaller( mySelfDependencyArrow.normalized()
102               .adjusted( extra, extra, -extra, -extra ) );
103     path.addPolygon( aPolygonBigger.subtracted( aPolygonSmaller ) );
104     path.addPolygon(myArrowHead);
105   }
106   else {
107     QPolygonF aShapePolygon;
108     QPolygon anArrowHead = myArrowHead.toPolygon();
109     QPolygon anReverseArrowHead = myReverseArrowHead.toPolygon();
110     aShapePolygon << anArrowHead.point(1) << anArrowHead.point(0) << anArrowHead.point(2) <<
111       anReverseArrowHead.point(1) << anReverseArrowHead.point(0) << anReverseArrowHead.point(2);
112     path.addPolygon( aShapePolygon );
113   }
114   return path;
115  }
116
117 //=================================================================================
118 // function : setColor()
119 // purpose  : set default color for arrow
120 //=================================================================================
121 void DependencyTree_Arrow::setColor( const QColor& theColor )
122 {
123   myColor = theColor;
124 }
125
126 //=================================================================================
127 // function : setHighlightColor()
128 // purpose  : set color for highlighted arrow
129 //=================================================================================
130 void DependencyTree_Arrow::setHighlightColor( const QColor& theColor )
131 {
132   myHighlightColor = theColor;
133 }
134
135 //=================================================================================
136 // function : setSelectColor()
137 // purpose  : set color for selected arrow
138 //=================================================================================
139 void DependencyTree_Arrow::setSelectColor( const QColor& theColor )
140 {
141   mySelectColor = theColor;
142 }
143
144 //=================================================================================
145 // function : getStartItem()
146 // purpose  : get start item of arrow
147 //=================================================================================
148 DependencyTree_Object* DependencyTree_Arrow::getStartItem() const
149 {
150   return myStartItem;
151 }
152
153 //=================================================================================
154 // function : getEndItem()
155 // purpose  : get end item of arrow
156 //=================================================================================
157 DependencyTree_Object* DependencyTree_Arrow::getEndItem() const
158 {
159   return myEndItem;
160 }
161
162 //=================================================================================
163 // function : setIsBiLink()
164 // purpose  : set true if current arrow is bi-directional link, else set false
165 //=================================================================================
166 void DependencyTree_Arrow::setIsBiLink( bool theIsBiLink )
167 {
168   myIsBiLink = theIsBiLink;
169 }
170
171 //=================================================================================
172 // function : paint()
173 // purpose  : paint the contents of an item in local coordinates (called by QGraphicsView)
174 //=================================================================================
175 void DependencyTree_Arrow::paint( QPainter* painter, const QStyleOptionGraphicsItem*, QWidget* )
176 {
177   if( isSelected() ) {
178     painter->setBrush( mySelectColor );
179     painter->setPen( QPen( mySelectColor, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin ) );
180   }
181   else if( isUnderMouse() ) {
182     painter->setBrush( myHighlightColor );
183     painter->setPen( QPen( myHighlightColor, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin ) );
184   }
185   else {
186     painter->setBrush( myColor );
187     painter->setPen( QPen( myColor, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin ) );
188   }
189
190   if( myStartItem == myEndItem ) {
191     int lineSize = 60;
192     QPointF p1( myStartItem->pos().x() - myStartItem->boundingRect().width()/2,
193                 myStartItem->pos().y() );
194     QPointF p2( p1.x() - lineSize + myStartItem->boundingRect().height()/2, p1.y() );
195     QPointF p3( p2.x(), p2.y() - lineSize );
196     QPointF p4( p3.x() + lineSize, p3.y() );
197     QPointF p5( p4.x(), p4.y() + lineSize - myStartItem->boundingRect().height()/2 );
198     mySelfDependencyArrow = QRectF( p3.x(), p3.y(), lineSize, lineSize );
199     myArrowHead = createArrowHead( p4, p5, false );
200     QVector<QPointF> pointVector;
201     pointVector << p1 << p2 << p2 << p3 << p3 << p4 << p4 << p5;
202
203     painter->drawLines( pointVector);
204     painter->drawPolygon(myArrowHead);
205   }
206   else {
207     if (myStartItem->collidesWithItem(myEndItem))
208       return;
209
210     myArrowHead  = createArrowHead( myStartItem->pos(), myEndItem->pos() );
211     myReverseArrowHead = createArrowHead( myEndItem->pos(), myStartItem->pos() );
212
213     painter->drawLine( myLine );
214     painter->drawPolygon( myArrowHead );
215     if( myIsBiLink )
216       painter->drawPolygon( myReverseArrowHead );
217   }
218 }
219
220 //=================================================================================
221 // function : createArrowHead()
222 // purpose  : create a head of arrow from start point to end point
223 //=================================================================================
224 QPolygonF DependencyTree_Arrow::createArrowHead( QPointF theStartPoint, QPointF theEndPoint,
225                                                          bool theIsDynamic )
226 {
227   if( theIsDynamic ) {
228     QLineF centerLine( theStartPoint, theEndPoint );
229     QPolygonF endPolygon = QPolygonF( myEndItem->boundingRect() );
230     QPointF p1 = endPolygon.first() + theEndPoint;
231     QPointF p2;
232     QPointF intersectPoint;
233     QLineF polyLine;
234     for( int i = 1; i < endPolygon.count(); ++i ) {
235       p2 = endPolygon.at(i) + theEndPoint;
236       polyLine = QLineF( p1, p2 );
237       QLineF::IntersectType intersectType = polyLine.intersect( centerLine, &intersectPoint );
238       if( intersectType == QLineF::BoundedIntersection )
239         break;
240       p1 = p2;
241     }
242     myLine = QLineF( intersectPoint, theStartPoint );
243   }
244   else
245     myLine = QLineF( theEndPoint, theStartPoint );
246
247   double angle = acos(myLine.dx() / myLine.length());
248   if( myLine.dy() >= 0 )
249     angle = ( M_PI * 2 ) - angle;
250
251   QPointF arrowP1 = myLine.p1() + QPointF( sin( angle + M_PI / 3 ) * arrowSize,
252                                            cos( angle + M_PI / 3 ) * arrowSize );
253   QPointF arrowP2 = myLine.p1() + QPointF( sin( angle + M_PI - M_PI / 3 ) * arrowSize,
254                                            cos( angle + M_PI - M_PI / 3 ) * arrowSize );
255
256   QPolygonF anArrowHead;
257   anArrowHead << myLine.p1() << arrowP1 << arrowP2;
258   return anArrowHead;
259 }